1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 03:40:34 +02:00

* src/objcodes.c (make_objcode_by_mmap): Fixed the error type when the

object file is too small.

* doc/guile-vm.texi:  Documented `make-closure'.  Improved the documentation
  of `load-program'.

* testsuite:  New directory.

* configure.in:  Added `testsuite/Makefile' to `AC_OUTPUT'.

* Makefile.am (SUBDIRS):  Added `testsuite'.

* src/vm_engine.h (VM_CHECK_OBJECT):  New option.
  (CHECK_OBJECT):  New macro.

* src/vm_system.c (object-ref):  Use VM_CHECK_OBJECT.

* module/system/vm/assemble.scm (preprocess):  Commented out the debugging
  code.

* benchmark/lib.scm (do-loop):  New procedure.

git-archimport-id: lcourtes@laas.fr--2005-mobile/guile-vm--mobile--0.6--patch-2
This commit is contained in:
Ludovic Courtes 2005-06-25 03:13:56 +00:00 committed by Ludovic Courtès
parent 6208295910
commit 0b5f0e49a8
22 changed files with 382 additions and 54 deletions

View file

@ -1,4 +1,4 @@
SUBDIRS = src doc module SUBDIRS = src doc module testsuite
EXTRA_DIST = acconfig.h EXTRA_DIST = acconfig.h

View file

@ -99,6 +99,13 @@
0 0
(loopi (1- n))))) (loopi (1- n)))))
(define (do-loop n)
;; Same as `loop' using `do'.
(do ((i n (1- i)))
((= 0 i))
;; do nothing
))
(define (do-cons x) (define (do-cons x)
;; This one shows that the built-in `cons' instruction yields a significant ;; This one shows that the built-in `cons' instruction yields a significant

View file

@ -23,4 +23,5 @@ AC_SUBST(GUILEC)
AC_OUTPUT(Makefile src/Makefile doc/Makefile module/Makefile AC_OUTPUT(Makefile src/Makefile doc/Makefile module/Makefile
module/system/Makefile module/system/base/Makefile module/system/Makefile module/system/base/Makefile
module/system/vm/Makefile module/system/il/Makefile module/system/vm/Makefile module/system/il/Makefile
module/system/repl/Makefile) module/system/repl/Makefile
testsuite/Makefile)

View file

@ -458,19 +458,6 @@ External function:
@section Subprogram call @section Subprogram call
@example
(define (plus a b) (+ a b))
(plus 1 2) ->
%pushi 1 ; argument 1
%pushi 2 ; argument 2
%loadt (plus . #<program xxx>) ; load the program
%call 2 ; call it with two arguments
%pushl (0 . 0) ; argument 1
%loadl (0 . 1) ; argument 2
add2 ; ac = 1 + 2
%return ; result is 3
@end example
@node Instruction Set, , Program Execution, Top @node Instruction Set, , Program Execution, Top
@chapter Instruction Set @chapter Instruction Set
@ -545,7 +532,13 @@ value of the closure variable located at @var{offset} within the
program's list of external variables. program's list of external variables.
@end deffn @end deffn
Let's look at a more complete example: @deffn @insn{} make-closure
Pop the program object from the stack and assign it the current
closure variable list as its closure. Push the result program
object.
@end deffn
Let's illustrate this:
@example @example
(let ((x 2)) (let ((x 2))
@ -560,16 +553,19 @@ The resulting program has one external (closure) variable, i.e. its
This yields the following code: This yields the following code:
@example @example
;; the traditional program prologue ;; the traditional program prologue with NLOCS = 0 and NEXTS = 1
0 (make-int8 2) 0 (make-int8 2)
2 (external-set 0) 2 (external-set 0)
4 (make-int8 4) 4 (make-int8 4)
6 (link "+") ;; lookup `+' 6 (link "+") ;; lookup `+'
9 (vector 1) ;; create the external variable vector for 9 (vector 1) ;; create the external variable vector for
;; later use by `object-ref' and `object-set' ;; later use by `object-ref' and `object-set'
... ...
40 (load-program ##34#) 40 (load-program ##34#)
59 (return) 59 (make-closure) ;; assign the current closure to the program
;; just pushed by `load-program'
60 (return)
@end example @end example
The program loaded here by @var{load-program} contains the following The program loaded here by @var{load-program} contains the following
@ -588,8 +584,8 @@ sequence of instructions:
16 (return) ;; return it 16 (return) ;; return it
@end example @end example
At this point, you know pretty much everything about the three types At this point, you should know pretty much everything about the three
of variables a program may need to access. types of variables a program may need to access.
@node Branch Instructions, Subprogram Control Instructions, Environment Control Instructions, Instruction Set @node Branch Instructions, Subprogram Control Instructions, Environment Control Instructions, Instruction Set
@ -656,15 +652,19 @@ parameter of every program.
@cindex Object table @cindex Object table
In order to handle such bindings, each program has an @dfn{object In order to handle such bindings, each program has an @dfn{object
table} associated to it. This table (actually a vector) contains all table} associated to it. This table (actually a Scheme vector)
the variable objects corresponding to the external bindings referenced contains all constant objects referenced by the program. The object
by the program. The object table of a program is initialized right table of a program is initialized right before a program is loaded
before a program is loaded and run with @var{load-program}. with @var{load-program}.
Therefore, external bindings only need to be looked up once before the Variable objects are one such type of constant object: when a global
program is loaded. References to the corresponding external variables binding is defined, a variable object is associated to it and that
from within the program are then performed via the @var{object-ref} object will remain constant over time, even if the value bound to it
instruction and are almost as fast as local variable references. changes. Therefore, external bindings only need to be looked up once
when the program is loaded. References to the corresponding external
variables from within the program are then performed via the
@var{object-ref} instruction and are almost as fast as local variable
references.
Let us consider the following program (procedure) which references Let us consider the following program (procedure) which references
external bindings @code{frob} and @var{%magic}: external bindings @code{frob} and @var{%magic}:
@ -698,7 +698,7 @@ argument which is the bytecode of the program itself. Disassembled,
this bytecode looks like: this bytecode looks like:
@example @example
z(object-ref 0) ;; push the variable object of `frob' (object-ref 0) ;; push the variable object of `frob'
(variable-ref) ;; dereference it (variable-ref) ;; dereference it
(local-ref 0) ;; push the value of `x' (local-ref 0) ;; push the value of `x'
(object-ref 1) ;; push the variable object of `%magic' (object-ref 1) ;; push the variable object of `%magic'

View file

@ -28,7 +28,7 @@
:use-module (ice-9 regex) :use-module (ice-9 regex)
:use-module (ice-9 common-list) :use-module (ice-9 common-list)
:use-module (srfi srfi-4) :use-module (srfi srfi-4)
:export (preprocess assemble)) :export (preprocess codegen assemble))
(define (assemble glil env . opts) (define (assemble glil env . opts)
(codegen (preprocess glil #f) #t)) (codegen (preprocess glil #f) #t))
@ -50,18 +50,26 @@
;;; ;;;
(define (preprocess x e) (define (preprocess x e)
; (format #t "entering~%")
(match x (match x
(($ <glil-asm> vars body) (($ <glil-asm> vars body)
(let* ((venv (<venv> :parent e :nexts vars.nexts :closure? #f)) ; (format #t "preparing to recurse~%")
(let* ((venv (<venv> :parent e :nexts (slot vars 'nexts) :closure? #f))
(body (map (lambda (x) (preprocess x venv)) body))) (body (map (lambda (x) (preprocess x venv)) body)))
(<vm-asm> :venv venv :glil x :body body))) (<vm-asm> :venv venv :glil x :body body)))
(($ <glil-external> op depth index) (($ <glil-external> op depth index)
(do ((d depth (1- d)) ; (format #t "preparing to return due to external: ~a ~a ~a [e=~a]~%"
(e e e.parent)) ; op depth index e)
(do ((d depth (- d 1))
(e e (slot e 'parent)))
((= d 0)) ((= d 0))
(set! e.closure? #t)) (set! (slot e 'closure?) #t))
; (format #t "returning due to external~%")
x) x)
(else x))) (else
(begin
; (format #t "returning~%")
x))))
;;; ;;;
@ -98,7 +106,7 @@
(match x (match x
(($ <vm-asm> venv) (($ <vm-asm> venv)
(push-object! (codegen x #f)) (push-object! (codegen x #f))
(if venv.closure? (push-code! `(make-closure)))) (if (slot venv 'closure?) (push-code! `(make-closure))))
(($ <glil-bind> binds) (($ <glil-bind> binds)
(let ((bindings (let ((bindings

View file

@ -82,9 +82,13 @@ make_objcode_by_mmap (int fd)
struct scm_objcode *p; struct scm_objcode *p;
ret = fstat (fd, &st); ret = fstat (fd, &st);
if ((ret < 0) || (st.st_size <= strlen (OBJCODE_COOKIE))) if (ret < 0)
SCM_SYSERROR; SCM_SYSERROR;
if (st.st_size <= strlen (OBJCODE_COOKIE))
scm_misc_error (FUNC_NAME, "object file too small (~a bytes)",
SCM_LIST1 (SCM_I_MAKINUM (st.st_size)));
addr = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); addr = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) if (addr == MAP_FAILED)
SCM_SYSERROR; SCM_SYSERROR;

View file

@ -58,6 +58,7 @@ vm_run (SCM vm, SCM program, SCM args)
struct scm_program *bp = NULL; /* program base pointer */ struct scm_program *bp = NULL; /* program base pointer */
SCM external = SCM_EOL; /* external environment */ SCM external = SCM_EOL; /* external environment */
SCM *objects = NULL; /* constant objects */ SCM *objects = NULL; /* constant objects */
size_t object_count; /* length of OBJECTS */
SCM *stack_base = vp->stack_base; /* stack base address */ SCM *stack_base = vp->stack_base; /* stack base address */
SCM *stack_limit = vp->stack_limit; /* stack limit address */ SCM *stack_limit = vp->stack_limit; /* stack limit address */
@ -138,8 +139,10 @@ vm_run (SCM vm, SCM program, SCM args)
goto vm_error; goto vm_error;
vm_error_wrong_type_apply: vm_error_wrong_type_apply:
err_msg = scm_from_locale_string ("VM: Wrong type to apply: ~S"); err_msg = scm_from_locale_string ("VM: Wrong type to apply: ~S "
err_args = SCM_LIST1 (program); "[IP offset: ~a]");
err_args = SCM_LIST2 (program,
SCM_I_MAKINUM (ip - bp->base));
goto vm_error; goto vm_error;
vm_error_stack_overflow: vm_error_stack_overflow:
@ -166,6 +169,13 @@ vm_run (SCM vm, SCM program, SCM args)
goto vm_error; goto vm_error;
#endif #endif
#if VM_CHECK_OBJECT
vm_error_object:
err_msg = scm_from_locale_string ("VM: Invalid object table access");
err_args = SCM_EOL;
goto vm_error;
#endif
vm_error: vm_error:
SYNC_ALL (); SYNC_ALL ();
vp->last_frame = vm_heapify_frames (vm); vp->last_frame = vm_heapify_frames (vm);

View file

@ -48,6 +48,7 @@
#define VM_USE_HOOKS 1 /* Various hooks */ #define VM_USE_HOOKS 1 /* Various hooks */
#define VM_USE_CLOCK 1 /* Bogoclock */ #define VM_USE_CLOCK 1 /* Bogoclock */
#define VM_CHECK_EXTERNAL 1 /* Check external link */ #define VM_CHECK_EXTERNAL 1 /* Check external link */
#define VM_CHECK_OBJECT 1 /* Check object table */
/* /*
@ -133,17 +134,16 @@
/* Get a local copy of the program's "object table" (i.e. the vector of /* Get a local copy of the program's "object table" (i.e. the vector of
external bindings that are referenced by the program), initialized by external bindings that are referenced by the program), initialized by
`load-program'. */ `load-program'. */
#define CACHE_PROGRAM() \ #define CACHE_PROGRAM() \
{ \ { \
size_t _vsize; \ ssize_t _vincr; \
ssize_t _vincr; \ scm_t_array_handle _vhandle; \
scm_t_array_handle _vhandle; \ \
\ bp = SCM_PROGRAM_DATA (program); \
bp = SCM_PROGRAM_DATA (program); \ /* Was: objects = SCM_VELTS (bp->objs); */ \
/* Was: objects = SCM_VELTS (bp->objs); */ \ objects = scm_vector_elements (bp->objs, &_vhandle, \
objects = scm_vector_elements (bp->objs, &_vhandle, \ &object_count, &_vincr); \
&_vsize, &_vincr); \ scm_array_handle_release (&_vhandle); \
scm_array_handle_release (&_vhandle); \
} }
#define SYNC_BEFORE_GC() \ #define SYNC_BEFORE_GC() \
@ -169,6 +169,14 @@
#define CHECK_EXTERNAL(e) #define CHECK_EXTERNAL(e)
#endif #endif
/* Accesses to a program's object table. */
#if VM_CHECK_OBJECT
#define CHECK_OBJECT(_num) \
do { if ((_num) >= object_count) goto vm_error_object; } while (0)
#else
#define CHECK_OBJECT(_num)
#endif
/* /*
* Hooks * Hooks

View file

@ -208,7 +208,9 @@ VM_DEFINE_INSTRUCTION (list_break, "list-break", 0, 0, 0)
VM_DEFINE_INSTRUCTION (object_ref, "object-ref", 1, 0, 1) VM_DEFINE_INSTRUCTION (object_ref, "object-ref", 1, 0, 1)
{ {
PUSH (OBJECT_REF (FETCH ())); register objnum = FETCH ();
CHECK_OBJECT (objnum);
PUSH (OBJECT_REF (objnum));
NEXT; NEXT;
} }

24
testsuite/Makefile.am Normal file
View file

@ -0,0 +1,24 @@
# The test programs.
# The Libtool executable.
GUILE_VM = $(top_srcdir)/src/guile-vm
vm_test_files = \
t-global-bindings.scm \
t-closure.scm \
t-closure2.scm \
t-closure3.scm \
t-do-loop.scm \
t-macros.scm \
t-proc-with-setter.scm \
t-values.scm \
t-records.scm \
t-match.scm
EXTRA_DIST = run-vm-tests.scm $(vm_test_files)
check:
$(GUILE_VM) -L $(top_srcdir)/module \
-l run-vm-tests.scm -e run-vm-tests \
$(vm_test_files)

View file

@ -0,0 +1,73 @@
;;; A simple test-running script.
(use-modules (system vm core)
(system vm disasm)
(system base compile)
(system base language)
(srfi srfi-1))
(define *scheme* (lookup-language 'scheme))
(define (fetch-sexp-from-file file)
(with-input-from-file file
(lambda ()
(let loop ((sexp (read))
(result '()))
(if (eof-object? sexp)
(cons 'begin (reverse result))
(loop (read) (cons sexp result)))))))
(define (compile-to-objcode sexp)
"Compile the expression @var{sexp} into a VM program and return it."
(compile-in sexp (current-module) *scheme*))
(define (run-vm-program objcode)
"Run VM program contained into @var{objcode}."
(vm-load (the-vm) objcode))
(define (run-test-from-file file)
"Run test from source file @var{file} and return a value indicating whether
it succeeded."
(run-vm-program (compile-to-objcode (fetch-sexp-from-file file))))
(define-macro (watch-proc proc-name str)
`(let ((orig-proc ,proc-name))
(set! ,proc-name
(lambda args
(format #t (string-append ,str "... "))
(apply orig-proc args)))))
(watch-proc fetch-sexp-from-file "reading")
(watch-proc compile-to-objcode "compiling")
(watch-proc run-vm-program "running")
;; The program.
(define (run-vm-tests files)
(let* ((res (map (lambda (file)
(format #t "running `~a'... " file)
(if (catch #t
(lambda ()
(run-test-from-file file))
(lambda (key . args)
(format #t "[~a/~a] " key args)
#f))
(format #t "ok~%")
(begin (format #t "FAILED~%") #f)))
files))
(total (length files))
(failed (length (filter not res))))
(if (= 0 failed)
(begin
(format #t "~%All ~a tests passed~%" total)
(exit 0))
(begin
(format #t "~%~a tests failed out of ~a~%"
failed total)
(exit failed)))))

5
testsuite/t-closure.scm Normal file
View file

@ -0,0 +1,5 @@
(let ((x 2))
(lambda ()
(let ((x++ (+ 1 x)))
(set! x x++)
x++)))

8
testsuite/t-closure2.scm Normal file
View file

@ -0,0 +1,8 @@
(define (uid)
(let* ((x 2)
(do-uid (lambda ()
(let ((x++ (+ 1 x)))
(set! x x++)
x++))))
(do-uid)))

5
testsuite/t-closure3.scm Normal file
View file

@ -0,0 +1,5 @@
(define (stuff)
(let* ((x 2)
(chbouib (lambda (z)
(+ 7 z x))))
(chbouib 77)))

5
testsuite/t-do-loop.scm Normal file
View file

@ -0,0 +1,5 @@
(let ((n+ 0))
(do ((n- 5 (1- n-))
(n+ n+ (1+ n+)))
((= n- 0))
(format #t "n- = ~a~%" n-)))

View file

@ -0,0 +1,13 @@
;; Are global bindings reachable at run-time? This relies on the
;; `object-ref' and `object-set' instructions.
(begin
(define the-binding "hello")
((lambda () the-binding))
((lambda () (set! the-binding "world")))
((lambda () the-binding)))

3
testsuite/t-macros.scm Normal file
View file

@ -0,0 +1,3 @@
;; Are macros well-expanded at compilation-time?
(false-if-exception (+ 2 2))

23
testsuite/t-match.scm Normal file
View file

@ -0,0 +1,23 @@
(use-modules (ice-9 match)
(srfi srfi-9)) ;; record type
(define-record-type <stuff>
(%make-stuff chbouib)
stuff?
(chbouib stuff:chbouib stuff:set-chbouib!))
(define (matches? obj)
; (format #t "matches? ~a~%" obj)
(match obj
(($ stuff) => #t)
; (blurps #t)
("hello" #t)
(else #f)))
;(format #t "go!~%")
(and (matches? (%make-stuff 12))
(matches? (%make-stuff 7))
(matches? "hello")
; (matches? 'blurps)
(not (matches? 66)))

View file

@ -0,0 +1,14 @@
(define the-struct (vector 1 2))
(define get/set
(make-procedure-with-setter
(lambda (struct name)
(case name
((first) (vector-ref struct 0))
((second) (vector-ref struct 1))
(else #f)))
(lambda (struct name val)
(case name
((first) (vector-set! struct 0 val))
((second) (vector-set! struct 1 val))
(else #f)))))

12
testsuite/t-records.scm Normal file
View file

@ -0,0 +1,12 @@
(use-modules (srfi srfi-9))
(define-record-type <stuff>
(%make-stuff chbouib)
stuff?
(chbouib stuff:chbouib stuff:set-chbouib!))
(and (stuff? (%make-stuff 12))
(= 7 (stuff:chbouib (%make-stuff 7)))
(not (stuff? 12))
(not (false-if-exception (%make-stuff))))

8
testsuite/t-values.scm Normal file
View file

@ -0,0 +1,8 @@
(use-modules (ice-9 receive))
(define (do-stuff x y)
(values x y))
(call-with-values (lambda () (values 1 2))
(lambda (x y) (cons x y)))

95
testsuite/the-bug.txt Normal file
View file

@ -0,0 +1,95 @@
-*- Outline -*-
Once (system vm assemble) is compiled, things start to fail in
unpredictable ways.
* `compile-file' of non-closure-using programs works
$ guile-disasm t-records.go > t-records.ref.asm
...
$ diff -uBb t-macros.*.asm
$ diff -uBb t-records.*.asm
$ diff -uBb t-global-bindings.*.asm
* `compile-file' of closure-using programs fails
ERROR: During compiling t-closure.scm:
ERROR: VM: Wrong type to apply: #(<venv> ((parent . #(<venv> ((parent . #f) (nexts . 1) (closure? . #f)))) (nexts . 0) (closure? . #f))) [IP offset: 28]
guile> (vm-debugger (the-vm))
debug> bt
#1 #<variable 30b12468 value: (#(<glil-asm> #(<glil-vars> ((nargs . 0) (nrest . 0) (nlocs . 0) (nexts . 1))) (#(<glil-const> 2) #(<glil-bind> ((x external 0))) #(<glil-external> set 0 0) #(<glil-asm> #(<glil-vars> ((nargs . 0) (nrest . 0) (nlocs . 1) (nexts . 0))) (#(<glil-module> ref #f +) #(<glil-const> 1) #(<glil-external> ref 1 0) #(<glil-call> call 2) #(<glil-source> (2 . 15)) #(<glil-bind> ((x++ local 0))) #(<glil-local> set 0) #(<glil-local> ref 0) #(<glil-external> set 1 0) #(<glil-local> ref 0) #(<glil-call> return 0) #(<glil-unbind>))) #(<glil-call> return 0) #(<glil-unbind>))) #<directory (guile-user) 100742d0> ())>
#2 (#<program 30ae74b8> #(<glil-vars> ...) (#(<glil-const> ...) #(<glil-bind> ...) ...))
#3 (#<program 30af7090>)
#4 (#<program 30af94c0> #(<glil-vars> ...) (#(<glil-module> ...) #(<glil-const> ...) ...))
#5 (#<program 30b00108>)
#6 (#<program 30b02590> ref ...)
#7 (_l 1 #(<venv> ...))
guile> (vm-debugger (the-vm))
debug> stack
(#t closure? #(<venv> ((parent . #(<venv> ((parent . #f) (nexts . 1) (closure? . #f)))) (nexts . 0) (closure? . #f))) #<procedure #f (struct name val)> #<primitive-generic map> #<primitive-generic map> #<program 30998470>)
* Compiling anything "by hand" fails
** Example 1: the read/compile/run loop
guile> (set! %load-path (cons "/home/ludo/src/guile-vm/module" %load-path))
guile> (use-modules (system vm assemble)(system vm core)(system repl repl))
guile> (start-repl 'scheme)
Guile Scheme interpreter 0.5 on Guile 1.7.2
Copyright (C) 2001 Free Software Foundation, Inc.
Enter `,help' for help.
scheme@guile-user> (use-modules (ice-9 match)
(system base syntax)
(system vm assemble))
(define (%preprocess x e)
(match x
(($ <glil-asm> vars body)
(let* ((venv (<venv> :parent e :nexts (slot vars 'nexts) :closure? #f))
(body (map (lambda (x) (preprocess x venv)) body)))
(<vm-asm> :venv venv :glil x :body body)))
(($ <glil-external> op depth index)
(do ((d depth (1- d))
(e e (slot e 'parent)))
((= d 0))
(set! (slot e 'closure?) #t))
x)
(else x)))
scheme@guile-user> preprocess
#<procedure preprocess (x e)>
scheme@guile-user> (getpid)
470
scheme@guile-user> (set! preprocess %preprocess)
scheme@guile-user> preprocess
ERROR: VM: Unbound variable: #<variable 30a0d5e0 value: #<undefined>>
scheme@guile-user> getpid
ERROR: VM: Unbound variable: #<variable 30a0d5e0 value: #<undefined>>
scheme@guile-user>
** Example 2: the test suite (which also reads/compiles/runs)
All the closure-using tests fail.
ludo@lully:~/src/guile-vm/testsuite $ make check
../src/guile-vm -L ../module \
-l run-vm-tests.scm -e run-vm-tests \
t-global-bindings.scm t-closure.scm t-closure2.scm t-closure3.scm t-do-loop.scm t-macros.scm t-proc-with-setter.scm t-values.scm t-records.scm t-match.scm
running `t-global-bindings.scm'... reading... compiling... running... ok
running `t-closure.scm'... reading... compiling... [vm-error/(vm-run VM: Wrong type to apply: ~S [IP offset: ~a] (#(<venv> ((parent . #(<venv> ((parent . #f) (nexts . 1) (closure? . #f)))) (nexts . 0) (closure? . #f))) 28))] FAILED
running `t-closure2.scm'... reading... compiling... [vm-error/(vm-run VM: Wrong type to apply: ~S [IP offset: ~a] (#(<venv> ((parent . #(<venv> ((parent . #(<venv> ((parent . #f) (nexts . 0) (closure? . #f)))) (nexts . 1) (closure? . #f)))) (nexts . 0) (closure? . #f))) 28))] FAILED
running `t-closure3.scm'... reading... compiling... [vm-error/(vm-run VM: Wrong ype to apply: ~S [IP offset: ~a] (#(<venv> ((parent . #(<venv> ((parent . #(<venv> ((parent . #f) (nexts . 0) (closure? . #f)))) (nexts . 1) (closure? . #f)))) (nexts . 0) (closure? . #f))) 28))] FAILED
running `t-do-loop.scm'... reading... compiling... [vm-error/(vm-run VM: Wrong type to apply: ~S [IP offset: ~a] (#(<venv> ((parent . #(<venv> ((parent . #f) (nexts . 1) (closure? . #f)))) (nexts . 0) (closure? . #f))) 28))] FAILED
running `t-macros.scm'... reading... compiling... running... ok
running `t-proc-with-setter.scm'... reading... compiling... running... ok
running `t-values.scm'... reading... compiling... running... ok
running `t-records.scm'... reading... compiling... running... ok
running `t-match.scm'... reading... compiling... running... ok
4 tests failed out of 10
make: *** [check] Error 4