Sorry for replying to my own message, but ... I've suggested before to Marc that he inline at least the fast path to read-char, so that would be about (from _io.scm): (define-prim (##read-char port) (##declare (not interrupts-enabled)) (macro-port-mutex-lock! port) ; get exclusive access to port (let loop () (let ((char-rlo (macro-character-port-rlo port)) (char-rhi (macro-character-port-rhi port))) (if (##fixnum.< char-rlo char-rhi) ; the next character is in the character read buffer (let ((c (##string-ref (macro-character-port-rbuf port) char- rlo))) (if (##not (##char=? c #\newline)) ; frequent simple case, just advance rlo (begin (macro-character-port-rlo-set! port (##fixnum.+ char- rlo 1)) (macro-port-mutex-unlock! port) c) .... plus some checking code that port is a character-input-port: (define-prim (read-char #!optional (port (macro-absent-obj))) (macro-force-vars (port) (let ((p (if (##eq? port (macro-absent-obj)) (macro-current-input-port) port))) (macro-check-character-input-port p 1 (read-char p) (##read-char p))))) Maybe that's still a good idea. The corresponding code in the standard C library is a macro that expands to something like this. Brad