%tc2-int 2) (define %tc3-imm24 4) (define %tc3-cons 0) (define %tc3-int1 %tc2-int) (define %tc3-int2 (+ %tc2-int 4)) (define %tc8-char (+ 8 %tc3-imm24)) (define %tc8-flag (+ %tc3-imm24 0)) ;; Cell types. (define %tc3-struct #x01) (define %tc7-symbol #x05) (define %tc7-variable #x07) (define %tc7-vector #x0d) (define %tc7-wvect #x0f) (define %tc7-string #x15) (define %tc7-number #x17) (define %tc7-hashtable #x1d) (define %tc7-pointer #x1f) (define %tc7-fluid #x25) (define %tc7-stringbuf #x27) (define %tc7-dynamic-state #x2d) (define %tc7-frame #x2f) (define %tc7-keyword #x35) (define %tc7-syntax #x3d) (define %tc7-program #x45) (define %tc7-vm-continuation #x47) (define %tc7-bytevector #x4d) (define %tc7-weak-set #x55) (define %tc7-weak-table #x57) (define %tc7-array #x5d) (define %tc7-bitvector #x5f) (define %tc7-port #x7d) (define %tc7-smob #x77) (define %tc16-bignum (+ %tc7-number (* 1 256))) (define %tc16-real (+ %tc7-number (* 2 256))) (define %tc16-complex (+ %tc7-number (* 3 256))) (define %tc16-fraction (+ %tc7-number (* 4 256))) ;; "Stringbufs". (define-record-type (stringbuf string) stringbuf? (string stringbuf-contents)) (set-record-type-printer! (lambda (stringbuf port) (display "#" port))) ;; Structs. (define-record-type (inferior-struct name fields) inferior-struct? (name inferior-struct-name) (fields inferior-struct-fields set-inferior-struct-fields!)) (define print-inferior-struct (let ((%printed-struct (make-parameter vlist-null))) (lambda (struct port) (if (vhash-assq struct (%printed-struct)) (format port "#-1#") (begin (format port "#" (object-address struct))))))) (set-record-type-printer! print-inferior-struct) ;; Object type to represent complex objects from the inferior process that ;; cannot be really converted to usable Scheme objects in the current ;; process. (define-record-type (%inferior-object kind sub-kind address) inferior-object? (kind inferior-object-kind) (sub-kind inferior-object-sub-kind) (address inferior-object-address)) (define inferior-object (case-lambda "Return an object representing an inferior object at ADDRESS, of type KIND/SUB-KIND." ((kind address) (%inferior-object kind #f address)) ((kind sub-kind address) (%inferior-object kind sub-kind address)))) (set-record-type-printer! (lambda (io port) (match io (($ kind sub-kind address) (format port "#<~a ~:[~*~;~a ~]~x>" kind sub-kind sub-kind address))))) (define (inferior-smob backend type-number address) "Return an object representing the SMOB at ADDRESS whose type is TYPE-NUMBER." (inferior-object 'smob (or (type-number->name backend 'smob type-number) type-number) address)) (define (inferior-port-type backend address) "Return an object representing the 'scm_t_port_type' structure at ADDRESS." (inferior-object 'port-type ;; The 'name' field lives at offset 0. (let ((name (dereference-word backend address))) (if (zero? name) "(nameless)" (read-c-string backend name))) address)) (define (inferior-port backend type-number address) "Return an object representing the port at ADDRESS whose type is TYPE-NUMBER." (inferior-object 'port (let ((address (+ address (* 3 %word-size)))) (inferior-port-type backend (dereference-word backend address))) address)) (define %visited-cells ;; Vhash of mapping addresses of already visited cells to the ;; corresponding inferior object. This is used to detect and represent ;; cycles. (make-parameter vlist-null)) (define-syntax visited (syntax-rules (->) ((_ (address -> object) body ...) (parameterize ((%visited-cells (vhash-consv address object (%visited-cells)))) body ...)))) (define (address->inferior-struct address vtable-data-address backend) "Read the struct at ADDRESS using BACKEND. Return an 'inferior-struct' object representing it." (define %vtable-layout-index 0) (define %vtable-name-index 5) (let* ((layout-address (+ vtable-data-address (* %vtable-layout-index %word-size))) (layout-bits (dereference-word backend layout-address)) (layout (scm->object layout-bits backend)) (name-address (+ vtable-data-address (* %vtable-name-index %word-size))) (name-bits (dereference-word backend name-address)) (name (scm->object name-bits backend))) (if (symbol? layout) (let* ((layout (symbol->string layout)) (len (/ (string-length layout) 2)) (slots (dereference-word backend (+ address %word-size))) (port (memory-port backend slots (* len %word-size))) (fields (get-bytevector-n port (* len %word-size))) (result (inferior-struct name #f))) ;; Keep track of RESULT so callees can refer to it if we are ;; decoding a circular struct. (visited (address -> result) (let ((values (map (cut scm->object <> backend) (bytevector->uint-list fields (native-endianness) %word-size)))) (set-inferior-struct-fields! result values) result))) (inferior-object 'invalid-struct address)))) (define* (cell->object address #:optional (backend %ffi-memory-backend)) "Return an object representing the object at ADDRESS, reading from memory using BACKEND." (or (and=> (vhash-assv address (%visited-cells)) cdr) ; circular object (let ((port (memory-port backend address))) (match-cell port (((vtable-data-address & 7 = %tc3-struct)) (address->inferior-struct address (- vtable-data-address %tc3-struct) backend)) (((_ & #x7f = %tc7-symbol) buf hash props) (match (cell->object buf backend) (($ string) (string->symbol string)))) (((_ & #x7f = %tc7-variable) obj) (inferior-object 'variable address)) (((_ & #x7f = %tc7-string) buf start len) (match (cell->object buf backend) (($ string) (substring string start (+ start len))))) (((_ & #x047f = %tc7-stringbuf) len (bytevector buf len)) (stringbuf (iconv:bytevector->string buf "ISO-8859-1"))) (((_ & #x047f = (bitwise-ior #x400 %tc7-stringbuf)) len (bytevector buf (* 4 len))) (stringbuf (iconv:bytevector->string buf (match (native-endianness) ('little "UTF-32LE") ('big "UTF-32BE"))))) (((_ & #x7f = %tc7-bytevector) len address) (let ((bv-port (memory-port backend address len))) (get-bytevector-n bv-port len))) ((((len << 8) || %tc7-vector)) (let ((words (get-bytevector-n port (* len %word-size))) (vector (make-vector len))) (visited (address -> vector) (fold (lambda (element index) (vector-set! vector index element) (+ 1 index)) 0 (map (cut scm->object <> backend) (bytevector->uint-list words (native-endianness) %word-size))) vector))) (((_ & #x7f = %tc7-wvect)) (inferior-object 'weak-vector address)) ; TODO: show elements (((_ & #x7f = %tc7-fluid) init-value) (inferior-object 'fluid address)) (((_ & #x7f = %tc7-dynamic-state)) (inferior-object 'dynamic-state address)) ((((flags << 8) || %tc7-port)) (inferior-port backend (logand flags #xff) address)) (((_ & #x7f = %tc7-program)) (inferior-object 'program address)) (((_ & #xffff = %tc16-bignum)) (inferior-object 'bignum address)) (((_ & #xffff = %tc16-real) pad) (let* ((address (+ address (* 2 %word-size))) (port (memory-port backend address (sizeof double))) (words (get-bytevector-n port (sizeof double)))) (bytevector-ieee-double-ref words 0 (native-endianness)))) (((_ & #x7f = %tc7-number) mpi) (inferior-object 'number address)) (((_ & #x7f = %tc7-hashtable) buckets meta-data unused) (inferior-object 'hash-table address)) (((_ & #x7f = %tc7-pointer) address) (make-pointer address)) (((_ & #x7f = %tc7-keyword) symbol) (symbol->keyword (cell->object symbol backend))) (((_ & #x7f = %tc7-syntax) expression wrap module) (cond-expand (guile-2.2 (make-syntax (cell->object expression backend) (cell->object wrap backend) (cell->object module backend))) (else (inferior-object 'syntax address)))) (((_ & #x7f = %tc7-vm-continuation)) (inferior-object 'vm-continuation address)) (((_ & #x7f = %tc7-weak-set)) (inferior-object 'weak-set address)) (((_ & #x7f = %tc7-weak-table)) (inferior-object 'weak-table address)) (((_ & #x7f = %tc7-array)) (inferior-object 'array address)) (((_ & #x7f = %tc7-bitvector)) (inferior-object 'bitvector address)) ((((smob-type << 8) || %tc7-smob) word1) (inferior-smob backend smob-type address)))))) (define* (scm->object bits #:optional (backend %ffi-memory-backend)) "Return the Scheme object corresponding to BITS, the bits of an 'SCM' object." (match-scm bits (((integer << 2) || %tc2-int) integer) ((address & 6 = %tc3-cons) (let* ((type (dereference-word backend address)) (pair? (not (bit-set? 0 type)))) (if pair? (or (and=> (vhash-assv address (%visited-cells)) cdr) (let ((car type) (cdrloc (+ address %word-size)) (pair (cons *unspecified* *unspecified*))) (visited (address -> pair) (set-car! pair (scm->object car backend)) (set-cdr! pair (scm->object (dereference-word backend cdrloc) backend)) pair))) (cell->object address backend)))) (((char << 8) || %tc8-char) (integer->char char)) (((flag << 8) || %tc8-flag) (case flag ((0) #f) ((1) #nil) ((3) '()) ((4) #t) ((8) (if #f #f)) ((9) (inferior-object 'undefined bits)) ((10) (eof-object)) ((11) (inferior-object 'unbound bits)))))) ;;; Local Variables: ;;; eval: (put 'match-scm 'scheme-indent-function 1) ;;; eval: (put 'match-cell 'scheme-indent-function 1) ;;; eval: (put 'visited 'scheme-indent-function 1) ;;; End: ;;; types.scm ends here