1638 lines
60 KiB
Scheme
1638 lines
60 KiB
Scheme
|
;;; library.ss
|
||
|
;;; Copyright 1984-2017 Cisco Systems, Inc.
|
||
|
;;;
|
||
|
;;; Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
;;; you may not use this file except in compliance with the License.
|
||
|
;;; You may obtain a copy of the License at
|
||
|
;;;
|
||
|
;;; http://www.apache.org/licenses/LICENSE-2.0
|
||
|
;;;
|
||
|
;;; Unless required by applicable law or agreed to in writing, software
|
||
|
;;; distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
;;; See the License for the specific language governing permissions and
|
||
|
;;; limitations under the License.
|
||
|
|
||
|
;;; Library entries should not contain references that could themselves
|
||
|
;;; compile into library entries. (Actually it will work as long as the
|
||
|
;;; use follows the definition, but...) Consequently they should be
|
||
|
;;; kept simple.
|
||
|
|
||
|
(eval-when (compile)
|
||
|
(optimize-level 3)
|
||
|
(generate-inspector-information #f)
|
||
|
($compile-profile #f)
|
||
|
($optimize-closures #t)
|
||
|
(run-cp0 (default-run-cp0))
|
||
|
(generate-interrupt-trap #f)
|
||
|
($track-dynamic-closure-counts #f))
|
||
|
|
||
|
(eval-when (compile)
|
||
|
(define-syntax define-library-entry
|
||
|
(lambda (x)
|
||
|
(define name->libspec
|
||
|
(lambda (name)
|
||
|
(or ($sgetprop name '*libspec* #f)
|
||
|
($oops 'define-library-entry "~s is undefined" name))))
|
||
|
(define name->does-not-expect-headroom-libspec
|
||
|
(lambda (name)
|
||
|
(or ($sgetprop name '*does-not-expect-headroom-libspec* #f)
|
||
|
($oops 'define-library-entry "~s is missing no headroom libspec" name))))
|
||
|
(syntax-case x ()
|
||
|
[(_ (name . args) e1 e2 ...)
|
||
|
(identifier? #'name)
|
||
|
(let ([libspec (name->libspec (datum name))]
|
||
|
[does-not-expect-headroom-libspec (name->does-not-expect-headroom-libspec (datum name))])
|
||
|
(with-syntax ([index (libspec-index libspec)]
|
||
|
[does-not-expect-headroom-index (libspec-index does-not-expect-headroom-libspec)]
|
||
|
[libspec (datum->syntax #'name libspec)]
|
||
|
[does-not-expect-headroom-libspec (datum->syntax #'name does-not-expect-headroom-libspec)])
|
||
|
; NB: we are duplicating code here, because looking up the library entry fails on startup.
|
||
|
#'(begin
|
||
|
($install-library-entry
|
||
|
'index
|
||
|
(case-lambda libspec (args e1 e2 ...)))
|
||
|
($install-library-entry
|
||
|
'does-not-expect-headroom-index
|
||
|
(case-lambda does-not-expect-headroom-libspec (args e1 e2 ...))))))])))
|
||
|
)
|
||
|
|
||
|
; we can't evaluate any dirty writes (eg. defines) until scan-remembered-set
|
||
|
; is ready, so install it up front.
|
||
|
(let ([install-library-entry ($hand-coded '$install-library-entry-procedure)])
|
||
|
(install-library-entry
|
||
|
(libspec-index (lookup-libspec scan-remembered-set))
|
||
|
($hand-coded 'scan-remembered-set)))
|
||
|
|
||
|
(let ([install-library-entry ($hand-coded '$install-library-entry-procedure)])
|
||
|
; no top-level defines before this point, or the linker won't have
|
||
|
; nonprocedure-code to insert in pvalue slot
|
||
|
(install-library-entry
|
||
|
(libspec-index (lookup-libspec nonprocedure-code))
|
||
|
($hand-coded 'nonprocedure-code)))
|
||
|
|
||
|
(define $foreign-entry ($hand-coded '$foreign-entry-procedure))
|
||
|
(define $install-library-entry
|
||
|
($hand-coded '$install-library-entry-procedure))
|
||
|
|
||
|
(eval-when (compile)
|
||
|
(define-syntax define-hand-coded-library-entry
|
||
|
(lambda (x)
|
||
|
(syntax-case x ()
|
||
|
((_ name)
|
||
|
(identifier? #'name)
|
||
|
#'($install-library-entry (libspec-index (lookup-libspec name))
|
||
|
($hand-coded 'name))))))
|
||
|
)
|
||
|
|
||
|
(define-hand-coded-library-entry get-room)
|
||
|
(define-hand-coded-library-entry call-error)
|
||
|
(define-hand-coded-library-entry dooverflood)
|
||
|
(define-hand-coded-library-entry dooverflow)
|
||
|
(define-hand-coded-library-entry dorest0)
|
||
|
(define-hand-coded-library-entry dorest1)
|
||
|
(define-hand-coded-library-entry dorest2)
|
||
|
(define-hand-coded-library-entry dorest3)
|
||
|
(define-hand-coded-library-entry dorest4)
|
||
|
(define-hand-coded-library-entry dorest5)
|
||
|
;;; doargerr must come before dounderflow*
|
||
|
(define-hand-coded-library-entry doargerr)
|
||
|
|
||
|
;;; dounderflow* must come before dounderflow
|
||
|
(define-library-entry (dounderflow* k args)
|
||
|
($do-wind ($current-winders) ($continuation-winders k))
|
||
|
(cond
|
||
|
((null? args) (k))
|
||
|
((null? (cdr args)) (k (car args)))
|
||
|
(else (#2%apply k args)))) ; library apply not available yet
|
||
|
|
||
|
;;; dounderflow & nuate must come before callcc
|
||
|
(define-hand-coded-library-entry dounderflow)
|
||
|
(define-hand-coded-library-entry nuate)
|
||
|
(define-hand-coded-library-entry callcc)
|
||
|
(define-hand-coded-library-entry call1cc)
|
||
|
(define-hand-coded-library-entry dofargint32)
|
||
|
(define-hand-coded-library-entry dofretint32)
|
||
|
(define-hand-coded-library-entry dofretuns32)
|
||
|
(define-hand-coded-library-entry dofargint64)
|
||
|
(define-hand-coded-library-entry dofretint64)
|
||
|
(define-hand-coded-library-entry dofretuns64)
|
||
|
(define-hand-coded-library-entry dofretu8*)
|
||
|
(define-hand-coded-library-entry dofretu16*)
|
||
|
(define-hand-coded-library-entry dofretu32*)
|
||
|
(define-hand-coded-library-entry domvleterr)
|
||
|
(define-hand-coded-library-entry values-error)
|
||
|
(define-hand-coded-library-entry bytevector=?)
|
||
|
|
||
|
(define $instantiate-code-object ($hand-coded '$instantiate-code-object))
|
||
|
|
||
|
;;; set up $nuate for overflow
|
||
|
(define $nuate ($closure-code (call/1cc (lambda (k) k))))
|
||
|
|
||
|
(set! #{raw-ref-count bhowt6w0coxl0s2y-1} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
(set! #{raw-create-count bhowt6w0coxl0s2y-2} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
(set! #{raw-alloc-count bhowt6w0coxl0s2y-3} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
(set! #{ref-count bhowt6w0coxl0s2y-4} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
(set! #{pair-create-count bhowt6w0coxl0s2y-5} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
(set! #{vector-create-count bhowt6w0coxl0s2y-6} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
(set! #{vector-alloc-count bhowt6w0coxl0s2y-8} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
(set! #{padded-vector-alloc-count bhowt6w0coxl0s2y-11} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
(set! #{closure-create-count bhowt6w0coxl0s2y-7} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
(set! #{closure-alloc-count bhowt6w0coxl0s2y-9} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
(set! #{padded-closure-alloc-count bhowt6w0coxl0s2y-10} '#[#{profile-counter b5vnnom9h4o4uny0-2} 0])
|
||
|
|
||
|
(let ()
|
||
|
(include "hashtable-types.ss")
|
||
|
(set! $eq-ht-rtd (record-type-descriptor eq-ht))
|
||
|
(set! $symbol-ht-rtd (record-type-descriptor symbol-ht)))
|
||
|
|
||
|
(define-library-entry (cfl* x y)
|
||
|
;; a+bi * c+di => ac-bd + (ad+bc)i
|
||
|
;; spurious overflows
|
||
|
(cond
|
||
|
[(flonum? x)
|
||
|
(if (flonum? y)
|
||
|
(fl* x y)
|
||
|
(fl-make-rectangular
|
||
|
(fl* x ($inexactnum-real-part y))
|
||
|
(fl* x ($inexactnum-imag-part y))))]
|
||
|
[(flonum? y)
|
||
|
(fl-make-rectangular
|
||
|
(fl* ($inexactnum-real-part x) y)
|
||
|
(fl* ($inexactnum-imag-part x) y))]
|
||
|
[else
|
||
|
(let ([a ($inexactnum-real-part x)] [b ($inexactnum-imag-part x)]
|
||
|
[c ($inexactnum-real-part y)] [d ($inexactnum-imag-part y)])
|
||
|
(fl-make-rectangular
|
||
|
(fl- (fl* a c) (fl* b d))
|
||
|
(fl+ (fl* a d) (fl* b c))))]))
|
||
|
|
||
|
(define-library-entry (cfl+ x y)
|
||
|
;; a+bi + c+di => (a+c) + (b+d)i
|
||
|
(cond
|
||
|
[(flonum? x)
|
||
|
(if (flonum? y)
|
||
|
(fl+ x y)
|
||
|
(fl-make-rectangular
|
||
|
(fl+ x ($inexactnum-real-part y))
|
||
|
($inexactnum-imag-part y)))]
|
||
|
[(flonum? y)
|
||
|
(fl-make-rectangular
|
||
|
(fl+ ($inexactnum-real-part x) y)
|
||
|
($inexactnum-imag-part x))]
|
||
|
[else
|
||
|
(fl-make-rectangular
|
||
|
(fl+ ($inexactnum-real-part x) ($inexactnum-real-part y))
|
||
|
(fl+ ($inexactnum-imag-part x) ($inexactnum-imag-part y)))]))
|
||
|
|
||
|
(define-library-entry (cfl- x y)
|
||
|
;; a+bi - c+di => (a-c) + (b-d)i
|
||
|
(cond
|
||
|
[(flonum? x)
|
||
|
(if (flonum? y)
|
||
|
(fl- x y)
|
||
|
(fl-make-rectangular
|
||
|
(fl- x ($inexactnum-real-part y))
|
||
|
(fl- ($inexactnum-imag-part y))))]
|
||
|
[(flonum? y)
|
||
|
(fl-make-rectangular
|
||
|
(fl- ($inexactnum-real-part x) y)
|
||
|
($inexactnum-imag-part x))]
|
||
|
[else
|
||
|
(fl-make-rectangular
|
||
|
(fl- ($inexactnum-real-part x) ($inexactnum-real-part y))
|
||
|
(fl- ($inexactnum-imag-part x) ($inexactnum-imag-part y)))]))
|
||
|
|
||
|
(define-library-entry (cfl/ x y)
|
||
|
;; spurious overflows, underflows, and division by zero
|
||
|
(cond
|
||
|
[(flonum? y)
|
||
|
;; a+bi/c => a/c + (b/c)i
|
||
|
(if (flonum? x)
|
||
|
(fl/ x y)
|
||
|
(fl-make-rectangular
|
||
|
(fl/ ($inexactnum-real-part x) y)
|
||
|
(fl/ ($inexactnum-imag-part x) y)))]
|
||
|
[(flonum? x)
|
||
|
;; a / c+di => c(a/(cc+dd)) + (-d(a/cc+dd))i
|
||
|
(let ([c ($inexactnum-real-part y)] [d ($inexactnum-imag-part y)])
|
||
|
(let ([t (fl/ x (fl+ (fl* c c) (fl* d d)))])
|
||
|
(fl-make-rectangular (fl* c t) (fl- (fl* d t)))))]
|
||
|
[else
|
||
|
;; a+bi / c+di => (ac+bd)/(cc+dd) + ((bc-ad)/(cc+dd))i
|
||
|
(let ([a ($inexactnum-real-part x)] [b ($inexactnum-imag-part x)]
|
||
|
[c ($inexactnum-real-part y)] [d ($inexactnum-imag-part y)])
|
||
|
(let ([t (fl+ (fl* c c) (fl* d d))])
|
||
|
(fl-make-rectangular (fl/ (fl+ (fl* a c) (fl* b d)) t)
|
||
|
(fl/ (fl- (fl* b c) (fl* a d)) t))))]))
|
||
|
|
||
|
(let ()
|
||
|
(define char-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a character" x)))
|
||
|
(define fixnum-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a fixnum" x)))
|
||
|
(define string-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a string" x)))
|
||
|
(define mutable-string-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a mutable string" x)))
|
||
|
(define vector-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a vector" x)))
|
||
|
(define mutable-vector-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a mutable vector" x)))
|
||
|
(define fxvector-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not an fxvector" x)))
|
||
|
(define mutable-fxvector-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a mutable fxvector" x)))
|
||
|
(define bytevector-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a bytevector" x)))
|
||
|
(define mutable-bytevector-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a mutable bytevector" x)))
|
||
|
(define index-oops
|
||
|
(lambda (who x i)
|
||
|
($oops who "~s is not a valid index for ~s" i x)))
|
||
|
|
||
|
(define-library-entry (char->integer x) (char-oops 'char->integer x))
|
||
|
|
||
|
(define-library-entry (string-ref s i)
|
||
|
(if (string? s)
|
||
|
(index-oops 'string-ref s i)
|
||
|
(string-oops 'string-ref s)))
|
||
|
|
||
|
(define-library-entry (string-set! s i c)
|
||
|
(if ($string-set!-check? s i)
|
||
|
(if (char? c)
|
||
|
(string-set! s i c)
|
||
|
(char-oops 'string-set! c))
|
||
|
(if (mutable-string? s)
|
||
|
(index-oops 'string-set! s i)
|
||
|
(mutable-string-oops 'string-set! s))))
|
||
|
|
||
|
(define-library-entry (string-length s)
|
||
|
(string-oops 'string-length s))
|
||
|
|
||
|
(define-library-entry (vector-ref v i)
|
||
|
(if (vector? v)
|
||
|
(index-oops 'vector-ref v i)
|
||
|
(vector-oops 'vector-ref v)))
|
||
|
|
||
|
(define-library-entry (vector-set! v i x)
|
||
|
(if (mutable-vector? v)
|
||
|
(index-oops 'vector-set! v i)
|
||
|
(mutable-vector-oops 'vector-set! v)))
|
||
|
|
||
|
(define-library-entry (vector-set-fixnum! v i x)
|
||
|
(if (fixnum? x)
|
||
|
(if (mutable-vector? v)
|
||
|
(index-oops 'vector-set-fixnum! v i)
|
||
|
(mutable-vector-oops 'vector-set-fixnum! v))
|
||
|
($oops 'vector-set-fixnum! "~s is not a fixnum" x)))
|
||
|
|
||
|
(define-library-entry (vector-length v)
|
||
|
(vector-oops 'vector-length v))
|
||
|
|
||
|
(define-library-entry (vector-cas! v i old-x new-x)
|
||
|
(if (mutable-vector? v)
|
||
|
(index-oops 'vector-cas! v i)
|
||
|
(mutable-vector-oops 'vector-cas! v)))
|
||
|
|
||
|
(define-library-entry (fxvector-ref v i)
|
||
|
(if (fxvector? v)
|
||
|
(index-oops 'fxvector-ref v i)
|
||
|
(fxvector-oops 'fxvector-ref v)))
|
||
|
|
||
|
(define-library-entry (fxvector-set! v i x)
|
||
|
(if (mutable-fxvector? v)
|
||
|
(if (and (fixnum? i) ($fxu< i (fxvector-length v)))
|
||
|
(fixnum-oops 'fxvector-set! x)
|
||
|
(index-oops 'fxvector-set! v i))
|
||
|
(mutable-fxvector-oops 'fxvector-set! v)))
|
||
|
|
||
|
(define-library-entry (fxvector-length v)
|
||
|
(fxvector-oops 'fxvector-length v))
|
||
|
|
||
|
(define-library-entry (bytevector-s8-ref v i)
|
||
|
(if (bytevector? v)
|
||
|
(index-oops 'bytevector-s8-ref v i)
|
||
|
(bytevector-oops 'bytevector-s8-ref v)))
|
||
|
|
||
|
(define-library-entry (bytevector-u8-ref v i)
|
||
|
(if (bytevector? v)
|
||
|
(index-oops 'bytevector-u8-ref v i)
|
||
|
(bytevector-oops 'bytevector-u8-ref v)))
|
||
|
|
||
|
(define-library-entry (bytevector-s8-set! v i k)
|
||
|
(if ($bytevector-set!-check? 8 v i)
|
||
|
(if (and (fixnum? k) (fx<= -128 k 127))
|
||
|
(bytevector-s8-set! v i k)
|
||
|
($oops 'bytevector-s8-set! "invalid value ~s" k))
|
||
|
(if (mutable-bytevector? v)
|
||
|
(index-oops 'bytevector-s8-set! v i)
|
||
|
(mutable-bytevector-oops 'bytevector-s8-set! v))))
|
||
|
|
||
|
(define-library-entry (bytevector-u8-set! v i k)
|
||
|
(if ($bytevector-set!-check? 8 v i)
|
||
|
(if (and (fixnum? k) (fx<= 0 k 255))
|
||
|
(bytevector-u8-set! v i k)
|
||
|
($oops 'bytevector-u8-set! "invalid value ~s" k))
|
||
|
(if (mutable-bytevector? v)
|
||
|
(index-oops 'bytevector-u8-set! v i)
|
||
|
(mutable-bytevector-oops 'bytevector-u8-set! v))))
|
||
|
|
||
|
(define-library-entry (bytevector-length v)
|
||
|
(bytevector-oops 'bytevector-length v))
|
||
|
|
||
|
(define-library-entry (char=? x y) (char-oops 'char=? (if (char? x) y x)))
|
||
|
(define-library-entry (char<? x y) (char-oops 'char<? (if (char? x) y x)))
|
||
|
(define-library-entry (char>? x y) (char-oops 'char>? (if (char? x) y x)))
|
||
|
(define-library-entry (char<=? x y) (char-oops 'char<=? (if (char? x) y x)))
|
||
|
(define-library-entry (char>=? x y) (char-oops 'char>=? (if (char? x) y x)))
|
||
|
)
|
||
|
|
||
|
(define-library-entry (real->flonum x who)
|
||
|
(cond
|
||
|
[(fixnum? x) (fixnum->flonum x)]
|
||
|
[(or (bignum? x) (ratnum? x)) (inexact x)]
|
||
|
[(flonum? x) x]
|
||
|
[else ($oops who "~s is not a real number" x)]))
|
||
|
|
||
|
(let ()
|
||
|
(define pair-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a pair" x)))
|
||
|
|
||
|
(define-library-entry (car x) (pair-oops 'car x))
|
||
|
(define-library-entry (cdr x) (pair-oops 'cdr x))
|
||
|
(define-library-entry (set-car! x y) (pair-oops 'set-car! x))
|
||
|
(define-library-entry (set-cdr! x y) (pair-oops 'set-cdr! x))
|
||
|
)
|
||
|
|
||
|
(let ()
|
||
|
(define c..r-oops
|
||
|
(lambda (who obj)
|
||
|
($oops who "incorrect list structure ~s" obj)))
|
||
|
|
||
|
(define-library-entry (caar x) (c..r-oops 'caar x))
|
||
|
(define-library-entry (cadr x) (c..r-oops 'cadr x))
|
||
|
(define-library-entry (cdar x) (c..r-oops 'cdar x))
|
||
|
(define-library-entry (cddr x) (c..r-oops 'cddr x))
|
||
|
(define-library-entry (caaar x) (c..r-oops 'caaar x))
|
||
|
(define-library-entry (caadr x) (c..r-oops 'caadr x))
|
||
|
(define-library-entry (cadar x) (c..r-oops 'cadar x))
|
||
|
(define-library-entry (caddr x) (c..r-oops 'caddr x))
|
||
|
(define-library-entry (cdaar x) (c..r-oops 'cdaar x))
|
||
|
(define-library-entry (cdadr x) (c..r-oops 'cdadr x))
|
||
|
(define-library-entry (cddar x) (c..r-oops 'cddar x))
|
||
|
(define-library-entry (cdddr x) (c..r-oops 'cdddr x))
|
||
|
(define-library-entry (caaaar x) (c..r-oops 'caaaar x))
|
||
|
(define-library-entry (caaadr x) (c..r-oops 'caaadr x))
|
||
|
(define-library-entry (caadar x) (c..r-oops 'caadar x))
|
||
|
(define-library-entry (caaddr x) (c..r-oops 'caaddr x))
|
||
|
(define-library-entry (cadaar x) (c..r-oops 'cadaar x))
|
||
|
(define-library-entry (cadadr x) (c..r-oops 'cadadr x))
|
||
|
(define-library-entry (caddar x) (c..r-oops 'caddar x))
|
||
|
(define-library-entry (cadddr x) (c..r-oops 'cadddr x))
|
||
|
(define-library-entry (cdaaar x) (c..r-oops 'cdaaar x))
|
||
|
(define-library-entry (cdaadr x) (c..r-oops 'cdaadr x))
|
||
|
(define-library-entry (cdadar x) (c..r-oops 'cdadar x))
|
||
|
(define-library-entry (cdaddr x) (c..r-oops 'cdaddr x))
|
||
|
(define-library-entry (cddaar x) (c..r-oops 'cddaar x))
|
||
|
(define-library-entry (cddadr x) (c..r-oops 'cddadr x))
|
||
|
(define-library-entry (cdddar x) (c..r-oops 'cdddar x))
|
||
|
(define-library-entry (cddddr x) (c..r-oops 'cddddr x))
|
||
|
)
|
||
|
|
||
|
(define-library-entry (unbox x)
|
||
|
($oops 'unbox "~s is not a box" x))
|
||
|
|
||
|
(define-library-entry (set-box! b v)
|
||
|
($oops 'set-box! "~s is not a mutable box" b))
|
||
|
|
||
|
(define-library-entry (box-cas! b old-v new-v)
|
||
|
($oops 'box-cas! "~s is not a mutable box" b))
|
||
|
|
||
|
(let ()
|
||
|
(define (fxnonfixnum1 who x)
|
||
|
($oops who "~s is not a fixnum" x))
|
||
|
|
||
|
(define (fxnonfixnum2 who x y)
|
||
|
($oops who "~s is not a fixnum" (if (fixnum? x) y x)))
|
||
|
|
||
|
(define (fxoops1 who x)
|
||
|
(if (fixnum? x)
|
||
|
($impoops who "fixnum overflow with argument ~s" x)
|
||
|
(fxnonfixnum1 who x)))
|
||
|
|
||
|
(define (fxoops2 who x y)
|
||
|
(if (fixnum? x)
|
||
|
(if (fixnum? y)
|
||
|
($impoops who "fixnum overflow with arguments ~s and ~s" x y)
|
||
|
(fxnonfixnum1 who y))
|
||
|
(fxnonfixnum1 who x)))
|
||
|
|
||
|
(define (shift-count-oops who x)
|
||
|
($oops who "invalid shift count ~s" x))
|
||
|
|
||
|
(define-library-entry (fx+ x y) (fxoops2 'fx+ x y))
|
||
|
(define-library-entry (fx- x y) (fxoops2 'fx- x y))
|
||
|
(define-library-entry (fx* x y) (fxoops2 'fx* x y))
|
||
|
(define-library-entry (fx1+ x) (fxoops1 'fx1+ x))
|
||
|
(define-library-entry (fx1- x) (fxoops1 'fx1- x))
|
||
|
|
||
|
(define-library-entry (fx= x y) (fxnonfixnum2 'fx= x y))
|
||
|
(define-library-entry (fx< x y) (fxnonfixnum2 'fx< x y))
|
||
|
(define-library-entry (fx> x y) (fxnonfixnum2 'fx> x y))
|
||
|
(define-library-entry (fx<= x y) (fxnonfixnum2 'fx<= x y))
|
||
|
(define-library-entry (fx>= x y) (fxnonfixnum2 'fx>= x y))
|
||
|
(define-library-entry (fx=? x y) (fxnonfixnum2 'fx=? x y))
|
||
|
(define-library-entry (fx<? x y) (fxnonfixnum2 'fx<? x y))
|
||
|
(define-library-entry (fx>? x y) (fxnonfixnum2 'fx>? x y))
|
||
|
(define-library-entry (fx<=? x y) (fxnonfixnum2 'fx<=? x y))
|
||
|
(define-library-entry (fx>=? x y) (fxnonfixnum2 'fx>=? x y))
|
||
|
(define-library-entry (fxzero? x) (fxnonfixnum1 'fxzero? x))
|
||
|
(define-library-entry (fxpositive? x) (fxnonfixnum1 'fxpositive? x))
|
||
|
(define-library-entry (fxnonpositive? x) (fxnonfixnum1 'fxnonpositive? x))
|
||
|
(define-library-entry (fxnegative? x) (fxnonfixnum1 'fxnegative? x))
|
||
|
(define-library-entry (fxnonnegative? x) (fxnonfixnum1 'fxnonnegative? x))
|
||
|
(define-library-entry (fxeven? x) (fxnonfixnum1 'fxeven? x))
|
||
|
(define-library-entry (fxodd? x) (fxnonfixnum1 'fxodd? x))
|
||
|
(define-library-entry (fxlogior x y) (fxnonfixnum2 'fxlogior x y))
|
||
|
(define-library-entry (fxlogor x y) (fxnonfixnum2 'fxlogor x y))
|
||
|
(define-library-entry (fxlogxor x y) (fxnonfixnum2 'fxlogxor x y))
|
||
|
(define-library-entry (fxlogand x y) (fxnonfixnum2 'fxlogand x y))
|
||
|
(define-library-entry (fxlognot x) (fxnonfixnum1 'fxlognot x))
|
||
|
(define-library-entry (fxior x y) (fxnonfixnum2 'fxior x y))
|
||
|
(define-library-entry (fxxor x y) (fxnonfixnum2 'fxxor x y))
|
||
|
(define-library-entry (fxand x y) (fxnonfixnum2 'fxand x y))
|
||
|
(define-library-entry (fxnot x) (fxnonfixnum1 'fxnot x))
|
||
|
|
||
|
(define-library-entry (fxsll x y)
|
||
|
(cond
|
||
|
[(not (fixnum? x)) (fxnonfixnum1 'fxsll x)]
|
||
|
[(not (fixnum? y)) (fxnonfixnum1 'fxsll y)]
|
||
|
[(fx= 0 y) x]
|
||
|
[($fxu< y (constant fixnum-bits))
|
||
|
(if (fx>= x 0)
|
||
|
(if (fx< x (fxsll 1 (fx- (- (constant fixnum-bits) 1) y)))
|
||
|
(fxsll x y)
|
||
|
(fxoops2 'fxsll x y))
|
||
|
(if (fx>= x (fxsll -1 (fx- (- (constant fixnum-bits) 1) y)))
|
||
|
(fxsll x y)
|
||
|
(fxoops2 'fxsll x y)))]
|
||
|
[(fx= y (constant fixnum-bits)) (if (fx= x 0) x (fxoops2 'fxsll x y))]
|
||
|
[else (shift-count-oops 'fxsll y)]))
|
||
|
|
||
|
(define-library-entry (fxarithmetic-shift-left x y)
|
||
|
(cond
|
||
|
[(not (fixnum? x)) (fxnonfixnum1 'fxarithmetic-shift-left x)]
|
||
|
[(not (fixnum? y)) (fxnonfixnum1 'fxarithmetic-shift-left y)]
|
||
|
[(fx= 0 y) x]
|
||
|
[($fxu< y (constant fixnum-bits))
|
||
|
(if (fx>= x 0)
|
||
|
(if (fx< x (fxsll 1 (fx- (- (constant fixnum-bits) 1) y)))
|
||
|
(fxsll x y)
|
||
|
(fxoops2 'fxarithmetic-shift-left x y))
|
||
|
(if (fx>= x (fxsll -1 (fx- (- (constant fixnum-bits) 1) y)))
|
||
|
(fxsll x y)
|
||
|
(fxoops2 'fxarithmetic-shift-left x y)))]
|
||
|
[else (shift-count-oops 'fxarithmetic-shift-left y)]))
|
||
|
|
||
|
(define-library-entry (fxsrl x y)
|
||
|
(cond
|
||
|
[(not (fixnum? x)) (fxnonfixnum1 'fxsrl x)]
|
||
|
[(not (fixnum? y)) (fxnonfixnum1 'fxsrl y)]
|
||
|
[else (shift-count-oops 'fxsrl y)]))
|
||
|
|
||
|
(define-library-entry (fxsra x y)
|
||
|
(cond
|
||
|
[(not (fixnum? x)) (fxnonfixnum1 'fxsra x)]
|
||
|
[(not (fixnum? y)) (fxnonfixnum1 'fxsra y)]
|
||
|
[else (shift-count-oops 'fxsra y)]))
|
||
|
|
||
|
(define-library-entry (fxarithmetic-shift-right x y)
|
||
|
(cond
|
||
|
[(not (fixnum? x)) (fxnonfixnum1 'fxarithmetic-shift-right x)]
|
||
|
[(not (fixnum? y)) (fxnonfixnum1 'fxarithmetic-shift-right y)]
|
||
|
[else (shift-count-oops 'fxarithmetic-shift-right y)]))
|
||
|
|
||
|
(define-library-entry (fxarithmetic-shift x y)
|
||
|
(cond
|
||
|
[(not (fixnum? x)) (fxnonfixnum1 'fxarithmetic-shift x)]
|
||
|
[(not (fixnum? y)) (fxnonfixnum1 'fxarithmetic-shift y)]
|
||
|
[(fx= 0 y) x]
|
||
|
[($fxu< y (constant fixnum-bits))
|
||
|
(if (fx>= x 0)
|
||
|
(if (fx< x (fxsll 1 (fx- (- (constant fixnum-bits) 1) y)))
|
||
|
(fxsll x y)
|
||
|
(fxoops2 'fxarithmetic-shift x y))
|
||
|
(if (fx>= x (fxsll -1 (fx- (- (constant fixnum-bits) 1) y)))
|
||
|
(fxsll x y)
|
||
|
(fxoops2 'fxarithmetic-shift x y)))]
|
||
|
[(fx< (fx- (constant fixnum-bits)) y 0) (fxsra x (fx- y))]
|
||
|
[else (shift-count-oops 'fxarithmetic-shift y)]))
|
||
|
|
||
|
(define-library-entry (fxlogbit? k n)
|
||
|
(if (fixnum? n)
|
||
|
(if (fixnum? k)
|
||
|
(if (fx< k 0)
|
||
|
($oops 'fxlogbit? "invalid bit index ~s" k)
|
||
|
; this case left to us by cp1in fxlogbit? handler
|
||
|
(fx< n 0))
|
||
|
(fxnonfixnum1 'fxlogbit? k))
|
||
|
(fxnonfixnum1 'fxlogbit? n)))
|
||
|
|
||
|
(define-library-entry (fxbit-set? n k)
|
||
|
(if (fixnum? n)
|
||
|
(if (fixnum? k)
|
||
|
(if (fx< k 0)
|
||
|
($oops 'fxbit-set? "invalid bit index ~s" k)
|
||
|
; this case left to us by cp1in fxbit-set? handler
|
||
|
(fx< n 0))
|
||
|
(fxnonfixnum1 'fxbit-set? k))
|
||
|
(fxnonfixnum1 'fxbit-set? n)))
|
||
|
|
||
|
(define-library-entry (fxlogbit0 k n)
|
||
|
(if (fixnum? n)
|
||
|
(if (fixnum? k)
|
||
|
($oops 'fxlogbit0 "invalid bit index ~s" k)
|
||
|
(fxnonfixnum1 'fxlogbit0 k))
|
||
|
(fxnonfixnum1 'fxlogbit0 n)))
|
||
|
|
||
|
(define-library-entry (fxlogbit1 k n)
|
||
|
(if (fixnum? n)
|
||
|
(if (fixnum? k)
|
||
|
($oops 'fxlogbit1 "invalid bit index ~s" k)
|
||
|
(fxnonfixnum1 'fxlogbit1 k))
|
||
|
(fxnonfixnum1 'fxlogbit1 n)))
|
||
|
|
||
|
(define-library-entry (fxcopy-bit n k)
|
||
|
; get here only if third argument is 0 or 1
|
||
|
(if (fixnum? n)
|
||
|
(if (fixnum? k)
|
||
|
($oops 'fxcopy-bit "invalid bit index ~s" k)
|
||
|
(fxnonfixnum1 'fxcopy-bit k))
|
||
|
(fxnonfixnum1 'fxcopy-bit n)))
|
||
|
|
||
|
(define-library-entry (fxlogtest x y) (fxnonfixnum2 'fxlogtest x y))
|
||
|
)
|
||
|
|
||
|
(let ()
|
||
|
(define flonum-oops
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not a flonum" x)))
|
||
|
|
||
|
(define-library-entry (fl= x y) (flonum-oops 'fl= (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl< x y) (flonum-oops 'fl< (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl> x y) (flonum-oops 'fl> (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl<= x y) (flonum-oops 'fl<= (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl>= x y) (flonum-oops 'fl>= (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl=? x y) (flonum-oops 'fl=? (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl<? x y) (flonum-oops 'fl<? (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl>? x y) (flonum-oops 'fl>? (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl<=? x y) (flonum-oops 'fl<=? (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl>=? x y) (flonum-oops 'fl>=? (if (flonum? x) y x)))
|
||
|
|
||
|
(define-library-entry (fl+ x y) (flonum-oops 'fl+ (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl- x y) (flonum-oops 'fl- (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl* x y) (flonum-oops 'fl* (if (flonum? x) y x)))
|
||
|
(define-library-entry (fl/ x y) (flonum-oops 'fl/ (if (flonum? x) y x)))
|
||
|
(define-library-entry (flnegate x) (flonum-oops 'fl- x))
|
||
|
)
|
||
|
|
||
|
(define-library-entry (flround x)
|
||
|
; assumes round-to-nearest-or-even
|
||
|
(float-type-case
|
||
|
[(ieee)
|
||
|
(define threshold+ #i#x10000000000000)
|
||
|
(define threshold- #i#x-10000000000000)])
|
||
|
(if (fl>= x 0.0)
|
||
|
(if (fl< x threshold+)
|
||
|
(fl- (fl+ x threshold+) threshold+)
|
||
|
x)
|
||
|
(if (fl> x threshold-)
|
||
|
(fl- (fl+ x threshold-) threshold-)
|
||
|
x)))
|
||
|
|
||
|
;;; The generic comparison entries assume the fixnum case is inlined.
|
||
|
|
||
|
(define-library-entry (= x y)
|
||
|
(cond
|
||
|
[(flonum? x)
|
||
|
(cond
|
||
|
[(flonum? y) (fl= x y)]
|
||
|
[($inexactnum? y) (and (fl= ($inexactnum-imag-part y) 0.0)
|
||
|
(fl= ($inexactnum-real-part y) x))]
|
||
|
[else ($= '= x y)])]
|
||
|
[($inexactnum? x)
|
||
|
(cond
|
||
|
[(flonum? y) (and (fl= ($inexactnum-imag-part x) 0.0)
|
||
|
(fl= ($inexactnum-real-part x) y))]
|
||
|
[($inexactnum? y)
|
||
|
(and (fl= ($inexactnum-imag-part x) ($inexactnum-imag-part y))
|
||
|
(fl= ($inexactnum-real-part x) ($inexactnum-real-part y)))]
|
||
|
[else ($= '= x y)])]
|
||
|
[else ($= '= x y)]))
|
||
|
|
||
|
(define-library-entry (zero? x)
|
||
|
(cond
|
||
|
[(cflonum? x) (cfl= x 0.0)]
|
||
|
[(or (bignum? x) (ratnum? x) ($exactnum? x)) #f]
|
||
|
[else ($= 'zero? x 0)]))
|
||
|
|
||
|
(define-library-entry (< x y)
|
||
|
(cond
|
||
|
[(and (flonum? x) (flonum? y)) (fl< x y)]
|
||
|
[else ($< '< x y)]))
|
||
|
|
||
|
(define-library-entry (> x y)
|
||
|
(cond
|
||
|
[(and (flonum? x) (flonum? y)) (fl> x y)]
|
||
|
[else ($< '> y x)]))
|
||
|
|
||
|
(define-library-entry (<= x y)
|
||
|
(cond
|
||
|
[(and (flonum? x) (flonum? y)) (fl<= x y)]
|
||
|
[else ($<= '<= x y)]))
|
||
|
|
||
|
(define-library-entry (>= x y)
|
||
|
(cond
|
||
|
[(and (flonum? x) (flonum? y)) (fl>= x y)]
|
||
|
[else ($<= '>= y x)]))
|
||
|
|
||
|
(define-library-entry (+ x y)
|
||
|
(cond
|
||
|
[(flonum? x)
|
||
|
(cond
|
||
|
[(flonum? y) (fl+ x y)]
|
||
|
[($inexactnum? y) (cfl+ x y)]
|
||
|
[else ($+ '+ x y)])]
|
||
|
[(and ($inexactnum? x) (cflonum? y)) (cfl+ x y)]
|
||
|
[else ($+ '+ x y)]))
|
||
|
|
||
|
(define-library-entry (1+ x)
|
||
|
(cond
|
||
|
[(flonum? x) (fl+ x 1.0)]
|
||
|
[($inexactnum? x) (cfl+ x 1.0)]
|
||
|
[else ($+ '1+ x 1)]))
|
||
|
|
||
|
(define-library-entry (add1 x)
|
||
|
(cond
|
||
|
[(flonum? x) (fl+ x 1.0)]
|
||
|
[($inexactnum? x) (cfl+ x 1.0)]
|
||
|
[else ($+ 'add1 x 1)]))
|
||
|
|
||
|
(define-library-entry (negate x)
|
||
|
(cond
|
||
|
[(flonum? x) (fl- x)]
|
||
|
[($inexactnum? x) (cfl- x)]
|
||
|
[else ($- '- 0 x)]))
|
||
|
|
||
|
(define-library-entry (- x y)
|
||
|
(cond
|
||
|
[(flonum? x)
|
||
|
(cond
|
||
|
[(flonum? y) (fl- x y)]
|
||
|
[($inexactnum? y) (cfl- x y)]
|
||
|
[else ($- '- x y)])]
|
||
|
[(and ($inexactnum? x) (cflonum? y)) (cfl- x y)]
|
||
|
[else ($- '- x y)]))
|
||
|
|
||
|
(define-library-entry (1- x)
|
||
|
(cond
|
||
|
[(flonum? x) (fl- x 1.0)]
|
||
|
[($inexactnum? x) (cfl- x 1.0)]
|
||
|
[else ($- '1- x 1)]))
|
||
|
|
||
|
(define-library-entry (-1+ x)
|
||
|
(cond
|
||
|
[(flonum? x) (fl- x 1.0)]
|
||
|
[($inexactnum? x) (cfl- x 1.0)]
|
||
|
[else ($- '-1+ x 1)]))
|
||
|
|
||
|
(define-library-entry (sub1 x)
|
||
|
(cond
|
||
|
[(flonum? x) (fl- x 1.0)]
|
||
|
[($inexactnum? x) (cfl- x 1.0)]
|
||
|
[else ($- 'sub1 x 1)]))
|
||
|
|
||
|
(define-library-entry (* x y)
|
||
|
(cond
|
||
|
[(flonum? x)
|
||
|
(cond
|
||
|
[(flonum? y) (fl* x y)]
|
||
|
[($inexactnum? y) (cfl* x y)]
|
||
|
[else ($* '* x y)])]
|
||
|
[(and ($inexactnum? x) (cflonum? y)) (cfl* x y)]
|
||
|
[else ($* '* x y)]))
|
||
|
|
||
|
(define-library-entry (/ x y)
|
||
|
(cond
|
||
|
[(flonum? x)
|
||
|
(cond
|
||
|
[(flonum? y) (fl/ x y)]
|
||
|
[($inexactnum? y) (cfl/ x y)]
|
||
|
[else ($/ '/ x y)])]
|
||
|
[(and ($inexactnum? x) (cflonum? y)) (cfl/ x y)]
|
||
|
[else ($/ '/ x y)]))
|
||
|
|
||
|
;;; The logical operators assume the fixnum case is inlined.
|
||
|
(let ()
|
||
|
(define exactintoops1
|
||
|
(lambda (who x)
|
||
|
($oops who "~s is not an exact integer" x)))
|
||
|
(define exactintoops2
|
||
|
(lambda (who x y)
|
||
|
(exactintoops1 who (if (or (fixnum? x) (bignum? x)) y x))))
|
||
|
|
||
|
(define-library-entry (logand x y)
|
||
|
(if (if (fixnum? x)
|
||
|
(bignum? y)
|
||
|
(and (bignum? x)
|
||
|
(or (fixnum? y) (bignum? y))))
|
||
|
($logand x y)
|
||
|
(exactintoops2 'logand x y)))
|
||
|
|
||
|
(define-library-entry (bitwise-and x y)
|
||
|
(if (if (fixnum? x)
|
||
|
(bignum? y)
|
||
|
(and (bignum? x)
|
||
|
(or (fixnum? y) (bignum? y))))
|
||
|
($logand x y)
|
||
|
(exactintoops2 'bitwise-and x y)))
|
||
|
|
||
|
(define-library-entry (logior x y) ; same as logor
|
||
|
(if (if (fixnum? x)
|
||
|
(bignum? y)
|
||
|
(and (bignum? x)
|
||
|
(or (fixnum? y) (bignum? y))))
|
||
|
($logor x y)
|
||
|
(exactintoops2 'logior x y)))
|
||
|
|
||
|
(define-library-entry (logor x y)
|
||
|
(if (if (fixnum? x)
|
||
|
(bignum? y)
|
||
|
(and (bignum? x)
|
||
|
(or (fixnum? y) (bignum? y))))
|
||
|
($logor x y)
|
||
|
(exactintoops2 'logor x y)))
|
||
|
|
||
|
(define-library-entry (bitwise-ior x y)
|
||
|
(if (if (fixnum? x)
|
||
|
(bignum? y)
|
||
|
(and (bignum? x)
|
||
|
(or (fixnum? y) (bignum? y))))
|
||
|
($logor x y)
|
||
|
(exactintoops2 'bitwise-ior x y)))
|
||
|
|
||
|
(define-library-entry (logxor x y)
|
||
|
(if (if (fixnum? x)
|
||
|
(bignum? y)
|
||
|
(and (bignum? x)
|
||
|
(or (fixnum? y) (bignum? y))))
|
||
|
($logxor x y)
|
||
|
(exactintoops2 'logxor x y)))
|
||
|
|
||
|
(define-library-entry (bitwise-xor x y)
|
||
|
(if (if (fixnum? x)
|
||
|
(bignum? y)
|
||
|
(and (bignum? x)
|
||
|
(or (fixnum? y) (bignum? y))))
|
||
|
($logxor x y)
|
||
|
(exactintoops2 'bitwise-xor x y)))
|
||
|
|
||
|
(define-library-entry (lognot x)
|
||
|
(if (bignum? x)
|
||
|
($lognot x)
|
||
|
(exactintoops1 'lognot x)))
|
||
|
|
||
|
(define-library-entry (bitwise-not x)
|
||
|
(if (bignum? x)
|
||
|
($lognot x)
|
||
|
(exactintoops1 'bitwise-not x)))
|
||
|
|
||
|
(let ()
|
||
|
(define (do-logbit? who k n)
|
||
|
(cond
|
||
|
[(fixnum? n)
|
||
|
(cond
|
||
|
[(fixnum? k)
|
||
|
(if (fx< k 0)
|
||
|
($oops who "invalid bit index ~s" k)
|
||
|
; this case left to us by cp1in logbit? handler
|
||
|
(fx< n 0))]
|
||
|
[(bignum? k)
|
||
|
(if (< k 0)
|
||
|
($oops who "invalid bit index ~s" k)
|
||
|
; this case left to us by cp1in logbit? handler
|
||
|
(fx< n 0))]
|
||
|
[else (exactintoops1 who k)])]
|
||
|
[(bignum? n)
|
||
|
(cond
|
||
|
[(fixnum? k)
|
||
|
(if (fx< k 0)
|
||
|
($oops who "invalid bit index ~s" k)
|
||
|
($logbit? k n))]
|
||
|
[(bignum? k)
|
||
|
(if (< k 0)
|
||
|
($oops who "invalid bit index ~s" k)
|
||
|
; $logbit? requires k to be a fixnum
|
||
|
(fxlogtest (ash n (- k)) 1))]
|
||
|
[else (exactintoops1 who k)])]
|
||
|
[else (exactintoops1 who n)]))
|
||
|
(define-library-entry (logbit? k n) (do-logbit? 'logbit? k n))
|
||
|
(define-library-entry (bitwise-bit-set? n k) (do-logbit? 'bitwise-bit-set? k n)))
|
||
|
|
||
|
(define-library-entry (logbit0 k n)
|
||
|
(if (or (fixnum? n) (bignum? n))
|
||
|
(cond
|
||
|
[(fixnum? k)
|
||
|
(if (fx< k 0)
|
||
|
($oops 'logbit0 "invalid bit index ~s" k)
|
||
|
($logbit0 k n))]
|
||
|
[(bignum? k)
|
||
|
(if (< k 0)
|
||
|
($oops 'logbit0 "invalid bit index ~s" k)
|
||
|
; $logbit0 requires k to be a fixnum
|
||
|
($logand n ($lognot (ash 1 k))))]
|
||
|
[else (exactintoops1 'logbit0 k)])
|
||
|
(exactintoops1 'logbit0 n)))
|
||
|
|
||
|
(define-library-entry (logbit1 k n)
|
||
|
(if (or (fixnum? n) (bignum? n))
|
||
|
(cond
|
||
|
[(fixnum? k)
|
||
|
(if (fx< k 0)
|
||
|
($oops 'logbit1 "invalid bit index ~s" k)
|
||
|
($logbit1 k n))]
|
||
|
[(bignum? k)
|
||
|
(if (< k 0)
|
||
|
($oops 'logbit1 "invalid bit index ~s" k)
|
||
|
; $logbit1 requires k to be a fixnum
|
||
|
($logor n (ash 1 k)))]
|
||
|
[else (exactintoops1 'logbit1 k)])
|
||
|
(exactintoops1 'logbit1 n)))
|
||
|
|
||
|
(define-library-entry (logtest x y)
|
||
|
(if (if (fixnum? x)
|
||
|
(bignum? y)
|
||
|
(and (bignum? x)
|
||
|
(or (fixnum? y) (bignum? y))))
|
||
|
($logtest x y)
|
||
|
(exactintoops2 'logtest x y)))
|
||
|
)
|
||
|
|
||
|
(let ()
|
||
|
(include "io-types.ss")
|
||
|
(define-syntax define-safe/unsafe
|
||
|
(lambda (x)
|
||
|
(syntax-case x ()
|
||
|
[(k (name arg ...) e ...)
|
||
|
(with-syntax ([safe-name (construct-name #'k "safe-" #'name)]
|
||
|
[unsafe-name (construct-name #'k "unsafe-" #'name)]
|
||
|
[who (datum->syntax #'k 'who)]
|
||
|
[check (datum->syntax #'k 'check)])
|
||
|
#'(let ()
|
||
|
(define who 'name)
|
||
|
(let ()
|
||
|
(define-syntax check (identifier-syntax if))
|
||
|
(define-library-entry (safe-name arg ...) e ...))
|
||
|
(let ()
|
||
|
(define-syntax check (syntax-rules () [(_ e1 e2 e3) e2]))
|
||
|
(define-library-entry (unsafe-name arg ...) e ...))))])))
|
||
|
(define-safe/unsafe (get-u8 p)
|
||
|
(check (and (input-port? p) (binary-port? p))
|
||
|
((port-handler-get ($port-handler p)) 'get-u8 p)
|
||
|
($oops who "~s is not a binary input port" p)))
|
||
|
(define-safe/unsafe (get-char p)
|
||
|
(check (and (input-port? p) (textual-port? p))
|
||
|
((port-handler-get ($port-handler p)) who p)
|
||
|
($oops who "~s is not a textual input port" p)))
|
||
|
(define-safe/unsafe (read-char p)
|
||
|
(check (and (input-port? p) (textual-port? p))
|
||
|
((port-handler-get ($port-handler p)) who p)
|
||
|
($oops who "~s is not a textual input port" p)))
|
||
|
(define-safe/unsafe (lookahead-u8 p)
|
||
|
(check (and (input-port? p) (binary-port? p))
|
||
|
((port-handler-lookahead ($port-handler p)) 'lookahead-u8 p)
|
||
|
($oops who "~s is not a binary input port" p)))
|
||
|
(define-safe/unsafe (lookahead-char p)
|
||
|
(check (and (input-port? p) (textual-port? p))
|
||
|
((port-handler-lookahead ($port-handler p)) who p)
|
||
|
($oops who "~s is not a textual input port" p)))
|
||
|
(define-safe/unsafe (peek-char p)
|
||
|
(check (and (input-port? p) (textual-port? p))
|
||
|
((port-handler-lookahead ($port-handler p)) who p)
|
||
|
($oops who "~s is not a textual input port" p)))
|
||
|
(define-safe/unsafe (unget-u8 p x)
|
||
|
(check (and (input-port? p) (binary-port? p))
|
||
|
(check (or (and (fixnum? x) (fx<= 0 x 255)) (eof-object? x))
|
||
|
((port-handler-unget ($port-handler p)) who p x)
|
||
|
($oops who "~s is not an octet or the eof object" x))
|
||
|
($oops who "~s is not a binary input port" p)))
|
||
|
(define-safe/unsafe (unget-char p x)
|
||
|
(check (and (input-port? p) (textual-port? p))
|
||
|
(check (or (char? x) (eof-object? x))
|
||
|
((port-handler-unget ($port-handler p)) who p x)
|
||
|
($oops who "~s is not an character or the eof object" x))
|
||
|
($oops who "~s is not a textual input port" p)))
|
||
|
(define-safe/unsafe (unread-char x p)
|
||
|
(check (and (input-port? p) (textual-port? p))
|
||
|
(check (or (char? x) (eof-object? x))
|
||
|
((port-handler-unget ($port-handler p)) who p x)
|
||
|
($oops who "~s is not an character or the eof object" x))
|
||
|
($oops who "~s is not a textual input port" p)))
|
||
|
(define-safe/unsafe (put-u8 p x)
|
||
|
(check (and (output-port? p) (binary-port? p))
|
||
|
(check (and (fixnum? x) (fx<= 0 x 255))
|
||
|
((port-handler-put ($port-handler p)) who p x)
|
||
|
($oops who "~s is not an octet" x))
|
||
|
($oops who "~s is not a binary output port" p)))
|
||
|
(define-safe/unsafe (put-char p x)
|
||
|
(check (and (output-port? p) (textual-port? p))
|
||
|
(check (char? x)
|
||
|
((port-handler-put ($port-handler p)) who p x)
|
||
|
($oops who "~s is not a character" x))
|
||
|
($oops who "~s is not a textual output port" p)))
|
||
|
(define-safe/unsafe (write-char x p)
|
||
|
(check (and (output-port? p) (textual-port? p))
|
||
|
(check (char? x)
|
||
|
((port-handler-put ($port-handler p)) who p x)
|
||
|
($oops who "~s is not a character" x))
|
||
|
($oops who "~s is not a textual output port" p)))
|
||
|
(define-safe/unsafe (newline p)
|
||
|
(check (and (output-port? p) (textual-port? p))
|
||
|
((port-handler-put ($port-handler p)) who p #\newline)
|
||
|
($oops who "~s is not a textual output port" p)))
|
||
|
(define-safe/unsafe (port-eof? p)
|
||
|
(check (input-port? p)
|
||
|
(eof-object? ((port-handler-lookahead ($port-handler p)) who p))
|
||
|
($oops who "~s is not an input port" p)))
|
||
|
(define-library-entry (put-bytevector bop bv start count)
|
||
|
(define who 'put-bytevector)
|
||
|
(if (or (fx> count max-put-copy) (fx> count (binary-port-output-count bop)))
|
||
|
(let ([put-some (port-handler-put-some ($port-handler bop))])
|
||
|
(let loop ([start start] [count count])
|
||
|
(unless (eq? 0 count)
|
||
|
(let ([n (put-some who bop bv start count)])
|
||
|
(loop (fx+ start n) (fx- count n))))))
|
||
|
(let ([i (binary-port-output-index bop)])
|
||
|
; counting on cp1in generating call to $byte-copy here and
|
||
|
; $byte-copy foreign procedure to be compiled w/o interrupt
|
||
|
; trap check in prims.ss. otherwise this won't be safe for
|
||
|
; multitasking.
|
||
|
(bytevector-copy! bv start (binary-port-output-buffer bop) i count)
|
||
|
(set-binary-port-output-index! bop (fx+ i count)))))
|
||
|
(define-library-entry (put-bytevector-some bop bv start count)
|
||
|
(define who 'put-bytevector-some)
|
||
|
(if (or (fx> count max-put-copy) (fx> count (binary-port-output-count bop)))
|
||
|
(let ([put-some (port-handler-put-some ($port-handler bop))])
|
||
|
(put-some who bop bv start count))
|
||
|
(let ([i (binary-port-output-index bop)])
|
||
|
; counting on cp1in generating call to $byte-copy here and
|
||
|
; $byte-copy foreign procedure to be compiled w/o interrupt
|
||
|
; trap check in prims.ss. otherwise this won't be safe for
|
||
|
; multitasking.
|
||
|
(bytevector-copy! bv start (binary-port-output-buffer bop) i count)
|
||
|
(set-binary-port-output-index! bop (fx+ i count))
|
||
|
count)))
|
||
|
(define-library-entry (put-string top st start count)
|
||
|
(define who 'put-string)
|
||
|
(if (or (fx> count max-put-copy) (fx> count (textual-port-output-count top)))
|
||
|
(let ([put-some (port-handler-put-some ($port-handler top))])
|
||
|
(let loop ([start start] [count count])
|
||
|
(unless (eq? 0 count)
|
||
|
(let ([n (put-some who top st start count)])
|
||
|
(loop (fx+ start n) (fx- count n))))))
|
||
|
(let ([i (textual-port-output-index top)])
|
||
|
; counting on cp1in generating call to $byte-copy here and
|
||
|
; $byte-copy foreign procedure to be compiled w/o interrupt
|
||
|
; trap check in prims.ss. otherwise this won't be safe for
|
||
|
; multitasking.
|
||
|
(string-copy! st start (textual-port-output-buffer top) i count)
|
||
|
(set-textual-port-output-index! top (fx+ i count)))))
|
||
|
(define-library-entry (put-string-some top st start count)
|
||
|
(define who 'put-string-some)
|
||
|
(if (or (fx> count max-put-copy) (fx> count (textual-port-output-count top)))
|
||
|
(let ([put-some (port-handler-put-some ($port-handler top))])
|
||
|
(put-some who top st start count))
|
||
|
(let ([i (textual-port-output-index top)])
|
||
|
; counting on cp1in generating call to $byte-copy here and
|
||
|
; $byte-copy foreign procedure to be compiled w/o interrupt
|
||
|
; trap check in prims.ss. otherwise this won't be safe for
|
||
|
; multitasking.
|
||
|
(string-copy! st start (textual-port-output-buffer top) i count)
|
||
|
(set-textual-port-output-index! top (fx+ i count))
|
||
|
count)))
|
||
|
(define-library-entry (display-string st top)
|
||
|
(define who 'display-string)
|
||
|
(let ([start 0] [count (string-length st)])
|
||
|
(if (or (fx> count max-put-copy) (fx> count (textual-port-output-count top)))
|
||
|
(let ([put-some (port-handler-put-some ($port-handler top))])
|
||
|
(let loop ([start start] [count count])
|
||
|
(unless (eq? 0 count)
|
||
|
(let ([n (put-some who top st start count)])
|
||
|
(loop (fx+ start n) (fx- count n))))))
|
||
|
(let ([i (textual-port-output-index top)])
|
||
|
; counting on cp1in generating call to $byte-copy here and
|
||
|
; $byte-copy foreign procedure to be compiled w/o interrupt
|
||
|
; trap check in prims.ss. otherwise this won't be safe for
|
||
|
; multitasking.
|
||
|
(string-copy! st start (textual-port-output-buffer top) i count)
|
||
|
(set-textual-port-output-index! top (fx+ i count))))))
|
||
|
)
|
||
|
|
||
|
(define-library-entry ($top-level-value x)
|
||
|
(unless (symbol? x)
|
||
|
($oops '$top-level-value "~s is not a symbol" x))
|
||
|
(unless ($top-level-bound? x)
|
||
|
($oops #f "variable ~:s is not bound" x))
|
||
|
(#3%$top-level-value x))
|
||
|
|
||
|
(define-library-entry (event)
|
||
|
(define (timer)
|
||
|
(if (eq? ($tc-field 'timer-ticks ($tc)) 0)
|
||
|
(let ([handler (timer-interrupt-handler)])
|
||
|
($tc-field 'timer-ticks ($tc) #f)
|
||
|
(signal)
|
||
|
(handler))
|
||
|
(signal)))
|
||
|
(define (signal)
|
||
|
(let ([x ($tc-field 'signal-interrupt-pending ($tc))])
|
||
|
(if x
|
||
|
(let ([handler $signal-interrupt-handler])
|
||
|
($tc-field 'signal-interrupt-pending ($tc) #f)
|
||
|
(keyboard)
|
||
|
(for-each handler ($dequeue-scheme-signals ($tc))))
|
||
|
(keyboard))))
|
||
|
(define (keyboard)
|
||
|
(if ($tc-field 'keyboard-interrupt-pending ($tc))
|
||
|
(let ([handler (keyboard-interrupt-handler)])
|
||
|
($tc-field 'keyboard-interrupt-pending ($tc) #f)
|
||
|
(collector)
|
||
|
(handler))
|
||
|
(collector)))
|
||
|
(define (collector)
|
||
|
(if $collect-request-pending
|
||
|
(let ([handler $collect-rendezvous])
|
||
|
(restart-timer)
|
||
|
(handler))
|
||
|
(restart-timer)))
|
||
|
(define (restart-timer)
|
||
|
(cond
|
||
|
[($tc-field 'timer-ticks ($tc)) =>
|
||
|
(lambda (t)
|
||
|
(let ([ticks (fxmin t (constant default-timer-ticks))])
|
||
|
($tc-field 'timer-ticks ($tc) (fx- t ticks))
|
||
|
($tc-field 'something-pending ($tc) #t)
|
||
|
($set-timer ticks)))]
|
||
|
[else
|
||
|
($set-timer (constant default-timer-ticks))]))
|
||
|
(if (and (fx= ($tc-field 'disable-count ($tc)) 0) ($tc-field 'something-pending ($tc)))
|
||
|
(begin
|
||
|
($set-timer (most-positive-fixnum))
|
||
|
($tc-field 'something-pending ($tc) #f)
|
||
|
(timer))
|
||
|
($set-timer (constant default-timer-ticks))))
|
||
|
|
||
|
(define-library-entry (virtual-register idx)
|
||
|
($oops 'virtual-register "invalid index ~s" idx))
|
||
|
|
||
|
(define-library-entry (set-virtual-register! idx)
|
||
|
($oops 'set-virtual-register! "invalid index ~s" idx))
|
||
|
|
||
|
(define-library-entry (map1 f ls)
|
||
|
(let map ([f f] [ls ls])
|
||
|
(if (null? ls)
|
||
|
'()
|
||
|
(let ((r (cdr ls)))
|
||
|
(if (null? r)
|
||
|
(list (f (car ls)))
|
||
|
; cdr first to avoid getting sick if f mutates input
|
||
|
(let ([tail (map f (cdr r))])
|
||
|
(list* (f (car ls)) (f (car r)) tail)))))))
|
||
|
|
||
|
(define-library-entry (map2 f ls1 ls2)
|
||
|
(let map ([f f] [ls1 ls1] [ls2 ls2])
|
||
|
(if (null? ls1)
|
||
|
'()
|
||
|
(let ((r1 (cdr ls1)))
|
||
|
(if (null? r1)
|
||
|
(list (f (car ls1) (car ls2)))
|
||
|
(let ((r2 (cdr ls2)))
|
||
|
; cdr first to avoid getting sick if f mutates input
|
||
|
(let ([tail (map f (cdr r1) (cdr r2))])
|
||
|
(list* (f (car ls1) (car ls2))
|
||
|
(f (car r1) (car r2))
|
||
|
tail))))))))
|
||
|
|
||
|
(define-library-entry (map-car ls)
|
||
|
(let map ([ls ls])
|
||
|
(if (null? ls)
|
||
|
'()
|
||
|
(let ((r (cdr ls)))
|
||
|
(if (null? r)
|
||
|
(list (car (car ls)))
|
||
|
(list* (car (car ls)) (car (car r)) (map (cdr r))))))))
|
||
|
|
||
|
(define-library-entry (map-cdr ls)
|
||
|
(let map ([ls ls])
|
||
|
(if (null? ls)
|
||
|
'()
|
||
|
(let ((r (cdr ls)))
|
||
|
(if (null? r)
|
||
|
(list (cdr (car ls)))
|
||
|
(list* (cdr (car ls)) (cdr (car r)) (map (cdr r))))))))
|
||
|
|
||
|
(define-library-entry (map-cons ls1 ls2)
|
||
|
(let map ([ls1 ls1] [ls2 ls2])
|
||
|
(if (null? ls1)
|
||
|
'()
|
||
|
(let ((r1 (cdr ls1)))
|
||
|
(if (null? r1)
|
||
|
(list (cons (car ls1) (car ls2)))
|
||
|
(let ((r2 (cdr ls2)))
|
||
|
(list* (cons (car ls1) (car ls2))
|
||
|
(cons (car r1) (car r2))
|
||
|
(map (cdr r1) (cdr r2)))))))))
|
||
|
|
||
|
(define-library-entry (for-each1 f ls)
|
||
|
(unless (null? ls)
|
||
|
(let for-each ([x (car ls)] [ls (cdr ls)])
|
||
|
(if (null? ls)
|
||
|
(f x)
|
||
|
(begin
|
||
|
(f x)
|
||
|
(for-each (car ls) (cdr ls)))))))
|
||
|
|
||
|
(define-library-entry (for-each2 f ls1 ls2)
|
||
|
(unless (null? ls1)
|
||
|
(let for-each ([x (car ls1)] [ls1 (cdr ls1)] [ls2 ls2])
|
||
|
(if (null? ls1)
|
||
|
(f x (car ls2))
|
||
|
(begin
|
||
|
(f x (car ls2))
|
||
|
(for-each (car ls1) (cdr ls1) (cdr ls2)))))))
|
||
|
|
||
|
(define-library-entry (andmap1 f ls)
|
||
|
(or (null? ls)
|
||
|
(let andmap ([ls ls])
|
||
|
(let ([x (car ls)] [ls (cdr ls)])
|
||
|
(if (null? ls)
|
||
|
(f x)
|
||
|
(and (f x) (andmap ls)))))))
|
||
|
|
||
|
(define-library-entry (ormap1 f ls)
|
||
|
(and (not (null? ls))
|
||
|
(let ormap ([ls ls])
|
||
|
(let ([x (car ls)] [ls (cdr ls)])
|
||
|
(if (null? ls)
|
||
|
(f x)
|
||
|
(or (f x) (ormap ls)))))))
|
||
|
|
||
|
(define-library-entry (vector-for-each1 p v)
|
||
|
(let ([n (vector-length v)])
|
||
|
(unless (fx= n 0)
|
||
|
(let loop ([i 0])
|
||
|
(let ([j (fx+ i 1)])
|
||
|
(if (fx= j n)
|
||
|
(p (vector-ref v i))
|
||
|
(begin
|
||
|
(p (vector-ref v i))
|
||
|
(loop j))))))))
|
||
|
|
||
|
(define-library-entry (vector-for-each2 p u v)
|
||
|
(let ([n (vector-length u)])
|
||
|
(unless (fx= n 0)
|
||
|
(let loop ([i 0])
|
||
|
(let ([j (fx+ i 1)])
|
||
|
(if (fx= j n)
|
||
|
(p (vector-ref u i) (vector-ref v i))
|
||
|
(begin
|
||
|
(p (vector-ref u i) (vector-ref v i))
|
||
|
(loop j))))))))
|
||
|
|
||
|
(define-library-entry (vector-map1 p v)
|
||
|
(let ([n (vector-length v)])
|
||
|
(let f ([i (fx- n 1)])
|
||
|
(if (fx> i 0)
|
||
|
(let ([x1 (p (vector-ref v i))] [x2 (p (vector-ref v (fx- i 1)))])
|
||
|
(let ([vout (f (fx- i 2))])
|
||
|
(vector-set! vout i x1)
|
||
|
(vector-set! vout (fx- i 1) x2)
|
||
|
vout))
|
||
|
(make-vector n (if (fx= i 0) (p (vector-ref v 0)) 0))))))
|
||
|
|
||
|
(define-library-entry (vector-map2 p u v)
|
||
|
(let ([n (vector-length u)])
|
||
|
(let f ([i (fx- n 1)])
|
||
|
(if (fx> i 0)
|
||
|
(let ([x1 (p (vector-ref u i) (vector-ref v i))]
|
||
|
[x2 (let ([j (fx- i 1)])
|
||
|
(p (vector-ref u j) (vector-ref v j)))])
|
||
|
(let ([vout (f (fx- i 2))])
|
||
|
(vector-set! vout i x1)
|
||
|
(vector-set! vout (fx- i 1) x2)
|
||
|
vout))
|
||
|
(make-vector n
|
||
|
(if (fx= i 0)
|
||
|
(p (vector-ref u 0) (vector-ref v 0))
|
||
|
0))))))
|
||
|
|
||
|
(define-library-entry (string-for-each1 p s)
|
||
|
(let ([n (string-length s)])
|
||
|
(unless (fx= n 0)
|
||
|
(let loop ([i 0])
|
||
|
(let ([j (fx+ i 1)])
|
||
|
(if (fx= j n)
|
||
|
(p (string-ref s i))
|
||
|
(begin
|
||
|
(p (string-ref s i))
|
||
|
(loop j))))))))
|
||
|
|
||
|
(define-library-entry (string-for-each2 p s t)
|
||
|
(let ([n (string-length s)])
|
||
|
(unless (fx= n 0)
|
||
|
(let loop ([i 0])
|
||
|
(let ([j (fx+ i 1)])
|
||
|
(if (fx= j n)
|
||
|
(p (string-ref s i) (string-ref t i))
|
||
|
(begin
|
||
|
(p (string-ref s i) (string-ref t i))
|
||
|
(loop j))))))))
|
||
|
|
||
|
(define-library-entry (fold-left1 combine nil ls)
|
||
|
(if (null? ls)
|
||
|
nil
|
||
|
(let fold-left ([ls ls] [acc nil])
|
||
|
(let ([cdrls (cdr ls)])
|
||
|
(if (null? cdrls)
|
||
|
(combine acc (car ls))
|
||
|
(fold-left cdrls (combine acc (car ls))))))))
|
||
|
|
||
|
(define-library-entry (fold-left2 combine nil ls1 ls2)
|
||
|
(if (null? ls1)
|
||
|
nil
|
||
|
(let fold-left ([ls1 ls1] [ls2 ls2] [acc nil])
|
||
|
(let ([cdrls1 (cdr ls1)])
|
||
|
(if (null? cdrls1)
|
||
|
(combine acc (car ls1) (car ls2))
|
||
|
(fold-left cdrls1 (cdr ls2)
|
||
|
(combine acc (car ls1) (car ls2))))))))
|
||
|
|
||
|
(define-library-entry (fold-right1 combine nil ls)
|
||
|
(let fold-right1 ([combine combine] [nil nil] [ls ls])
|
||
|
(if (null? ls)
|
||
|
nil
|
||
|
; naturally does cdrs first to avoid mutation sickness
|
||
|
(combine (car ls) (fold-right1 combine nil (cdr ls))))))
|
||
|
|
||
|
(define-library-entry (fold-right2 combine nil ls1 ls2)
|
||
|
(let fold-right2 ([combine combine] [nil nil] [ls1 ls1] [ls2 ls2])
|
||
|
(if (null? ls1)
|
||
|
nil
|
||
|
; naturally does cdrs first to avoid mutation sickness
|
||
|
(combine (car ls1) (car ls2)
|
||
|
(fold-right2 combine nil (cdr ls1) (cdr ls2))))))
|
||
|
|
||
|
(eval-when (compile)
|
||
|
(define-syntax doapply
|
||
|
(syntax-rules ()
|
||
|
[(_ p (x ...) ls) (if (null? ls) (p x ...) (doapply p (x ...) ls (ls)))]
|
||
|
[(_ p (x ...) ls (ls1 ... lsn))
|
||
|
(= (length #'(ls1 ...)) 4)
|
||
|
($apply p (fx+ (length '(x ...)) (length '(ls1 ...)) (length lsn))
|
||
|
(list* x ... ls))]
|
||
|
[(_ p (x ...) ls (ls1 ... lsn-1))
|
||
|
(let ([lsn (cdr lsn-1)])
|
||
|
(if (null? lsn)
|
||
|
(p x ... (car ls1) ... (car lsn-1))
|
||
|
(doapply p (x ...) ls (ls1 ... lsn-1 lsn))))]))
|
||
|
)
|
||
|
|
||
|
(define-library-entry (apply0 p ls)
|
||
|
(doapply p () ls))
|
||
|
|
||
|
(define-library-entry (apply1 p x1 ls)
|
||
|
(doapply p (x1) ls))
|
||
|
|
||
|
(define-library-entry (apply2 p x1 x2 ls)
|
||
|
(doapply p (x1 x2) ls))
|
||
|
|
||
|
(define-library-entry (apply3 p x1 x2 x3 ls)
|
||
|
(doapply p (x1 x2 x3) ls))
|
||
|
|
||
|
(define-library-entry (eqv? x y)
|
||
|
(if (eq? x y)
|
||
|
#t
|
||
|
(exclusive-cond
|
||
|
[(flonum? x) (and (flonum? y) ($fleqv? x y))]
|
||
|
[($inexactnum? x)
|
||
|
(and ($inexactnum? y)
|
||
|
($fleqv? ($inexactnum-real-part x) ($inexactnum-real-part y))
|
||
|
($fleqv? ($inexactnum-imag-part x) ($inexactnum-imag-part y)))]
|
||
|
[(bignum? x) (and (bignum? y) (= x y))]
|
||
|
[(ratnum? x) (and (ratnum? y) (= x y))]
|
||
|
[($exactnum? x) (and ($exactnum? y) (= x y))]
|
||
|
[else #f])))
|
||
|
|
||
|
(define-library-entry (memv x ls)
|
||
|
(if (or (symbol? x) (#%$immediate? x))
|
||
|
(memq x ls)
|
||
|
(let memv ([ls ls])
|
||
|
(and (not (null? ls))
|
||
|
(if (eqv? (car ls) x)
|
||
|
ls
|
||
|
(let ([ls (cdr ls)])
|
||
|
(and (not (null? ls))
|
||
|
(if (eqv? (car ls) x)
|
||
|
ls
|
||
|
(memv (cdr ls))))))))))
|
||
|
|
||
|
(define-library-entry (reverse ls)
|
||
|
(let loop ([ls ls] [a '()])
|
||
|
(if (null? ls)
|
||
|
a
|
||
|
(let ([ls2 (cdr ls)])
|
||
|
(if (null? ls2)
|
||
|
(cons (car ls) a)
|
||
|
(loop (cdr ls2) (cons* (car ls2) (car ls) a)))))))
|
||
|
|
||
|
(let ()
|
||
|
(include "hashtable-types.ss")
|
||
|
|
||
|
;;; eq hashtable operations must be compiled with
|
||
|
;;; generate-interrupt-trap #f and optimize-level 3
|
||
|
;;; so they can't be interrupted by a collection
|
||
|
(let ()
|
||
|
(define-syntax lookup-keyval
|
||
|
(syntax-rules ()
|
||
|
[(_ ?x ?b succ fail)
|
||
|
(let ([x ?x])
|
||
|
(let loop ([b ?b])
|
||
|
(if (fixnum? b)
|
||
|
fail
|
||
|
(let ([keyval ($tlc-keyval b)])
|
||
|
(if (eq? (car keyval) x)
|
||
|
(succ keyval)
|
||
|
(loop ($tlc-next b)))))))]))
|
||
|
|
||
|
(define-syntax incr-size!
|
||
|
(syntax-rules ()
|
||
|
[(_ h vec)
|
||
|
(let ([size (fx+ (ht-size h) 1)] [n (vector-length vec)])
|
||
|
(ht-size-set! h size)
|
||
|
(when (and (fx> size n) (fx< n (fxsrl (most-positive-fixnum) 1)))
|
||
|
(adjust! h vec n (fxsll n 1))))]))
|
||
|
|
||
|
(define-syntax decr-size!
|
||
|
(syntax-rules ()
|
||
|
[(_ h vec)
|
||
|
(let ([size (fx- (ht-size h) 1)] [n (vector-length vec)])
|
||
|
(ht-size-set! h size)
|
||
|
(when (and (fx< size (fxsrl n 2)) (fx> n (ht-minlen h)))
|
||
|
(let ([target (fxmax (fxsll size 2) (ht-minlen h))])
|
||
|
(let loop ([n2 n])
|
||
|
(let ([n2 (fxsrl n2 1)])
|
||
|
(if (fx<= n2 target)
|
||
|
(adjust! h vec n n2)
|
||
|
(loop n2)))))))]))
|
||
|
|
||
|
(define adjust!
|
||
|
(lambda (h vec1 n1 n2)
|
||
|
(let ([vec2 ($make-eqhash-vector n2)] [mask2 (fx- n2 1)])
|
||
|
(do ([i1 0 (fx+ i1 1)])
|
||
|
((fx= i1 n1))
|
||
|
(let loop ([b (vector-ref vec1 i1)])
|
||
|
(unless (fixnum? b)
|
||
|
(let ([next ($tlc-next b)] [keyval ($tlc-keyval b)])
|
||
|
(let ([i2 (fxlogand ($fxaddress (car keyval)) mask2)])
|
||
|
($set-tlc-next! b (vector-ref vec2 i2))
|
||
|
(vector-set! vec2 i2 b))
|
||
|
(loop next)))))
|
||
|
(ht-vec-set! h vec2))))
|
||
|
|
||
|
(define-library-entry (eq-hashtable-ref h x v)
|
||
|
(lookup-keyval x
|
||
|
(let ([vec (ht-vec h)])
|
||
|
(vector-ref vec (fxlogand ($fxaddress x) (fx- (vector-length vec) 1))))
|
||
|
cdr v))
|
||
|
|
||
|
(define-library-entry (eq-hashtable-contains? h x)
|
||
|
(lookup-keyval x
|
||
|
(let ([vec (ht-vec h)])
|
||
|
(vector-ref vec (fxlogand ($fxaddress x) (fx- (vector-length vec) 1))))
|
||
|
(lambda (x) #t)
|
||
|
#f))
|
||
|
|
||
|
(define-library-entry (eq-hashtable-cell h x v)
|
||
|
(let* ([vec (ht-vec h)]
|
||
|
[idx (fxlogand ($fxaddress x) (fx- (vector-length vec) 1))]
|
||
|
[b (vector-ref vec idx)])
|
||
|
(lookup-keyval x b
|
||
|
values
|
||
|
(let ([keyval (let ([subtype (eq-ht-subtype h)])
|
||
|
(cond
|
||
|
[(eq? subtype (constant eq-hashtable-subtype-normal)) (cons x v)]
|
||
|
[(eq? subtype (constant eq-hashtable-subtype-weak)) (weak-cons x v)]
|
||
|
[else (ephemeron-cons x v)]))])
|
||
|
(vector-set! vec idx ($make-tlc h keyval b))
|
||
|
(incr-size! h vec)
|
||
|
keyval))))
|
||
|
|
||
|
(let ()
|
||
|
(define do-set!
|
||
|
(lambda (h x v)
|
||
|
(let* ([vec (ht-vec h)]
|
||
|
[idx (fxlogand ($fxaddress x) (fx- (vector-length vec) 1))]
|
||
|
[b (vector-ref vec idx)])
|
||
|
(lookup-keyval x b
|
||
|
(lambda (keyval) (set-cdr! keyval v))
|
||
|
(begin
|
||
|
(vector-set! vec idx
|
||
|
($make-tlc h
|
||
|
(let ([subtype (eq-ht-subtype h)])
|
||
|
(cond
|
||
|
[(eq? subtype (constant eq-hashtable-subtype-normal)) (cons x v)]
|
||
|
[(eq? subtype (constant eq-hashtable-subtype-weak)) (weak-cons x v)]
|
||
|
[else (ephemeron-cons x v)]))
|
||
|
b))
|
||
|
(incr-size! h vec))))))
|
||
|
|
||
|
(define-library-entry (eq-hashtable-set! h x v)
|
||
|
(do-set! h x v))
|
||
|
|
||
|
(define-library-entry (eq-hashtable-update! h x p v)
|
||
|
(let* ([vec (ht-vec h)]
|
||
|
[idx (fxlogand ($fxaddress x) (fx- (vector-length vec) 1))]
|
||
|
[b (vector-ref vec idx)])
|
||
|
(lookup-keyval x b
|
||
|
(lambda (a) (set-cdr! a (p (cdr a))))
|
||
|
(do-set! h x (p v))))))
|
||
|
|
||
|
(define-library-entry (eq-hashtable-delete! h x)
|
||
|
(let* ([vec (ht-vec h)]
|
||
|
[idx (fxlogand ($fxaddress x) (fx- (vector-length vec) 1))]
|
||
|
[b (vector-ref vec idx)])
|
||
|
(unless (fixnum? b)
|
||
|
(if (eq? (car ($tlc-keyval b)) x)
|
||
|
(begin
|
||
|
(vector-set! vec idx ($tlc-next b))
|
||
|
($set-tlc-next! b #f)
|
||
|
(decr-size! h vec))
|
||
|
(let loop ([b b])
|
||
|
(let ([n ($tlc-next b)])
|
||
|
(unless (fixnum? n)
|
||
|
(if (eq? (car ($tlc-keyval n)) x)
|
||
|
(begin
|
||
|
($set-tlc-next! b ($tlc-next n))
|
||
|
($set-tlc-next! n #f)
|
||
|
(decr-size! h vec))
|
||
|
(loop n)))))))))
|
||
|
)
|
||
|
|
||
|
; symbol hashtable operations
|
||
|
(let ()
|
||
|
(define-syntax incr-size!
|
||
|
(syntax-rules ()
|
||
|
[(_ h vec)
|
||
|
(let ([size (fx+ (ht-size h) 1)] [n (vector-length vec)])
|
||
|
(ht-size-set! h size)
|
||
|
(when (and (fx> size n) (fx< n (fxsrl (most-positive-fixnum) 1)))
|
||
|
(adjust! h vec (fxsll n 1))))]))
|
||
|
|
||
|
(define-syntax decr-size!
|
||
|
(syntax-rules ()
|
||
|
[(_ h vec)
|
||
|
(let ([size (fx- (ht-size h) 1)] [n (vector-length vec)])
|
||
|
(ht-size-set! h size)
|
||
|
(when (and (fx< size (fxsrl n 2)) (fx> n (ht-minlen h)))
|
||
|
(adjust! h vec (fxsrl n 1))))]))
|
||
|
|
||
|
(define adjust!
|
||
|
(lambda (h vec1 n2)
|
||
|
(let ([vec2 (make-vector n2 '())]
|
||
|
[mask2 (fx- n2 1)])
|
||
|
(vector-for-each
|
||
|
(lambda (b)
|
||
|
(for-each
|
||
|
(lambda (a)
|
||
|
(let ([hc (fxlogand ($symbol-hash (car a)) mask2)])
|
||
|
(vector-set! vec2 hc (cons a (vector-ref vec2 hc)))))
|
||
|
b))
|
||
|
vec1)
|
||
|
(ht-vec-set! h vec2))))
|
||
|
|
||
|
(define-library-entry (symbol-hashtable-ref h x v)
|
||
|
(let ([hc ($symbol-hash x)])
|
||
|
(if hc
|
||
|
(let ([vec (ht-vec h)])
|
||
|
(let loop ([b (vector-ref vec (fxlogand hc (fx- (vector-length vec) 1)))])
|
||
|
(if (null? b)
|
||
|
v
|
||
|
(let ([a (car b)])
|
||
|
(if (eq? (car a) x) (cdr a) (loop (cdr b)))))))
|
||
|
(pariah v))))
|
||
|
|
||
|
(define-library-entry (symbol-hashtable-contains? h x)
|
||
|
(let ([hc ($symbol-hash x)])
|
||
|
(and hc
|
||
|
(let ([vec (ht-vec h)])
|
||
|
(let loop ([b (vector-ref vec (fxlogand hc (fx- (vector-length vec) 1)))])
|
||
|
(and (not (null? b))
|
||
|
(or (eq? (caar b) x)
|
||
|
(loop (cdr b)))))))))
|
||
|
|
||
|
(define-library-entry (symbol-hashtable-cell h x v)
|
||
|
(let ([vec (ht-vec h)] [hc ($symbol-hash x)])
|
||
|
(if hc
|
||
|
(let ([idx (fxlogand hc (fx- (vector-length vec) 1))])
|
||
|
(let ([bucket (vector-ref vec idx)])
|
||
|
(let loop ([b bucket])
|
||
|
(if (null? b)
|
||
|
(let ([a (cons x v)])
|
||
|
(vector-set! vec idx (cons a bucket))
|
||
|
(incr-size! h vec)
|
||
|
a)
|
||
|
(let ([a (car b)])
|
||
|
(if (eq? (car a) x)
|
||
|
a
|
||
|
(loop (cdr b))))))))
|
||
|
(let ([idx (fxlogand (symbol-hash x) (fx- (vector-length vec) 1))])
|
||
|
(let ([a (cons x v)])
|
||
|
(vector-set! vec idx (cons a (vector-ref vec idx)))
|
||
|
(incr-size! h vec)
|
||
|
a)))))
|
||
|
|
||
|
(define-library-entry (symbol-hashtable-set! h x v)
|
||
|
(let ([vec (ht-vec h)] [hc ($symbol-hash x)])
|
||
|
(if hc
|
||
|
(let ([idx (fxlogand hc (fx- (vector-length vec) 1))])
|
||
|
(let ([bucket (vector-ref vec idx)])
|
||
|
(let loop ([b bucket])
|
||
|
(if (null? b)
|
||
|
(begin
|
||
|
(vector-set! vec idx (cons (cons x v) bucket))
|
||
|
(incr-size! h vec))
|
||
|
(let ([a (car b)])
|
||
|
(if (eq? (car a) x) (set-cdr! a v) (loop (cdr b))))))))
|
||
|
(let ([idx (fxlogand (symbol-hash x) (fx- (vector-length vec) 1))])
|
||
|
(vector-set! vec idx (cons (cons x v) (vector-ref vec idx)))
|
||
|
(incr-size! h vec)))))
|
||
|
|
||
|
(define-library-entry (symbol-hashtable-update! h x p v)
|
||
|
(let ([vec (ht-vec h)] [hc ($symbol-hash x)])
|
||
|
(if hc
|
||
|
(let ([idx (fxlogand hc (fx- (vector-length vec) 1))])
|
||
|
(let ([bucket (vector-ref vec idx)])
|
||
|
(let loop ([b bucket])
|
||
|
(if (null? b)
|
||
|
(begin
|
||
|
(vector-set! vec idx (cons (cons x (p v)) bucket))
|
||
|
(incr-size! h vec))
|
||
|
(let ([a (car b)])
|
||
|
(if (eq? (car a) x)
|
||
|
(set-cdr! a (p (cdr a)))
|
||
|
(loop (cdr b))))))))
|
||
|
(let ([idx (fxlogand (symbol-hash x) (fx- (vector-length vec) 1))])
|
||
|
(vector-set! vec idx (cons (cons x (p v)) (vector-ref vec idx)))
|
||
|
(incr-size! h vec)))))
|
||
|
|
||
|
(define-library-entry (symbol-hashtable-delete! h x)
|
||
|
(let ([hc ($symbol-hash x)])
|
||
|
(when hc
|
||
|
(let ([vec (ht-vec h)])
|
||
|
(let ([idx (fxlogand hc (fx- (vector-length vec) 1))])
|
||
|
(let loop ([b (vector-ref vec idx)] [p #f])
|
||
|
(unless (null? b)
|
||
|
(let ([a (car b)])
|
||
|
(if (eq? (car a) x)
|
||
|
(begin
|
||
|
(if p (set-cdr! p (cdr b)) (vector-set! vec idx (cdr b)))
|
||
|
(decr-size! h vec))
|
||
|
(loop (cdr b) b))))))))))
|
||
|
)
|
||
|
)
|
||
|
|
||
|
;;; the routines below may cause significant allocation without any
|
||
|
;;; embedded calls to other trap-checking routines, so we enable
|
||
|
;;; generation-interrupt-trap for them.
|
||
|
(eval-when (compile) (generate-interrupt-trap #t))
|
||
|
|
||
|
(define-library-entry (append ls1 ls2)
|
||
|
(let append ([ls1 ls1] [ls2 ls2])
|
||
|
(if (null? ls1)
|
||
|
ls2
|
||
|
(let ((cdr-ls1 (cdr ls1)))
|
||
|
(if (null? cdr-ls1)
|
||
|
(cons (car ls1) ls2)
|
||
|
(list* (car ls1) (car cdr-ls1) (append (cdr cdr-ls1) ls2)))))))
|