Add support for record types with anonymous fields

Avoid saving a list of per-field vector descriptions when
field names are not going to be relevant and the rest of
the description is easily computed from information that is
alerady available.

original commit: a20e3f305cee3b4a386582dd50cda344a49174c3
This commit is contained in:
Matthew Flatt 2020-02-10 10:33:27 -07:00
parent 5d45d6dca2
commit aa0c555c70
13 changed files with 504 additions and 183 deletions

View File

@ -4105,6 +4105,17 @@ The field names are symbols.
(record-type-field-names (type-descriptor triple)) ;=> (x1 x2 x3)
\endschemedisplay
%----------------------------------------------------------------------------
\entryheader
\formdef{record-type-field-names}{\categoryprocedure}{(record-type-field-indices \var{rtd})}
\returns a list of field indicies of the type represented by \var{rtd}
\listlibraries
\endentryheader
\noindent
\var{rtd} must be a record-type descriptor.
The field indices are fixnums.
%----------------------------------------------------------------------------
\entryheader
\formdef{record-type-field-decls}{\categoryprocedure}{(record-type-field-decls \var{rtd})}
@ -4187,6 +4198,38 @@ rtd ;=> #<record type frob>
(eq? (record-type-descriptor x) rtd) ;=> \var{unspecified}
\endschemedisplay
%----------------------------------------------------------------------------
\entryheader
\formdef{make-record-type-descriptor*}{\categoryprocedure}{(make-record-type-descriptor* \var{name} \var{parent} \var{uid} \var{s?} \var{o?} \var{fields} \var{mutability})}
\returns a record-type descriptor for a new record type
\listlibraries
\endentryheader
\noindent
This variant of \scheme{make-record-type-descriptor} accepts a field
count and mutability mask in place of a vector of field descriptions,
which results in a record type with anonymous fields. The \var{fields}
argument must be a non-negative fixnum for the field count, and it is
added to any fields present in \var{parent} to determine the record
type's total numnber of fields. The \var{mutability} argument must be
an exact non-negative integer that is treated as a bit array; a
\scheme{1} bit indicates the the corresponding field among
\var{fields} is mutable.
If \var{parent} is a record type descriptor, it must also have
anonymous fields. The resulting anonynmous-field record type can only
be the parent of a record type with anonymous fields.
%----------------------------------------------------------------------------
\entryheader
\formdef{record-type-named-fields?}{\categoryprocedure}{(record-type-named-fields? \var{rtd})}
\returns a boolean indicating whether \var{rts} has named fields
\listlibraries
\endentryheader
\noindent
\var{rtd} must be a record-type descriptor.
\section{Procedures}

View File

@ -62,7 +62,7 @@ InstallLZ4Target=
# no changes should be needed below this point #
###############################################################################
Version=csv9.5.3.19
Version=csv9.5.3.20
Include=boot/$m
PetiteBoot=boot/$m/petite.boot
SchemeBoot=boot/$m/scheme.boot

View File

@ -328,7 +328,7 @@
[(_ foo e1 e2) e1] ...
[(_ bar e1 e2) e2]))))])))
(define-constant scheme-version #x09050313)
(define-constant scheme-version #x09050314)
(define-syntax define-machine-types
(lambda (x)
@ -1461,11 +1461,11 @@
(define-primitive-structure-disps record-type type-typed-object
([ptr type]
[ptr parent]
[ptr size]
[ptr pm]
[ptr mpm]
[ptr size] ; total record size in bytes, including type tag
[ptr pm] ; pointer mask, where low bit corresponds to type tag
[ptr mpm] ; mutable-pointer mask, where low bit for type is always 0
[ptr name]
[ptr flds]
[ptr flds] ; either a list of `fld` vectors or a fixnum count
[ptr flags]
[ptr uid]
[ptr counts]))

148
s/cp0.ss
View File

@ -123,6 +123,7 @@
(define rtd-parent (csv7:record-field-accessor #!base-rtd 'parent))
(define rtd-size (csv7:record-field-accessor #!base-rtd 'size))
(define rtd-pm (csv7:record-field-accessor #!base-rtd 'pm))
(define rtd-mpm (csv7:record-field-accessor #!base-rtd 'mpm))
; compile-time rtds (ctrtds)
(define ctrtd-opaque-known #b0000001)
@ -142,6 +143,39 @@
(or (not (ctrtd? rtd))
(fxlogtest (ctrtd-flags rtd) ctrtd-opaque-known))))
(define rtd-all-immutable?
(lambda (rtd)
(let ([flds (rtd-flds rtd)])
(cond
[(fixnum? flds) (eqv? 0 (rtd-mpm rtd))]
[else
(andmap (lambda (fld) (not (fld-mutable? fld))) flds)]))))
(define rtd-all-immutable-scheme-objects?
(lambda (rtd)
(let ([flds (rtd-flds rtd)])
(cond
[(fixnum? flds)
(eqv? 0 (rtd-mpm rtd))]
[else
(andmap (lambda (fld)
(and (not (fld-mutable? fld))
(eq? (filter-foreign-type (fld-type fld)) 'scheme-object)))
flds)]))))
(define rtd-immutable-field?
(lambda (rtd index)
(let ([flds (rtd-flds rtd)])
(cond
[(fixnum? flds)
(not (bitwise-bit-set? (rtd-mpm rtd) (fx+ index 1)))]
[else
(not (fld-mutable? (list-ref flds index)))]))))
(define rtd-make-fld
(lambda (rtd index)
(make-fld 'unknown (bitwise-bit-set? (rtd-mpm rtd) (fx+ index 1)) 'scheme-object 0)))
(with-output-language (Lsrc Expr)
(define void-rec `(quote ,(void)))
(define true-rec `(quote #t))
@ -551,17 +585,20 @@
; from a rhs.
[(record ,rtd ,rtd-expr ,e* ...)
(let-values ([(liftmt* liftme* e*)
(let ([fld* (rtd-flds rtd)])
(let f ([e* e*] [fld* fld*])
(let ([fld* (rtd-flds rtd)]
[mpm (rtd-mpm rtd)])
(let f ([e* e*] [fld* (and (not (fixnum? fld*)) fld*)] [idx 0])
(if (null? e*)
(values '() '() '())
(let ([e (car e*)])
(let-values ([(liftmt* liftme* e*) (f (cdr e*) (cdr fld*))])
(let-values ([(liftmt* liftme* e*) (f (cdr e*) (and fld* (cdr fld*)) (fx+ idx 1))])
(if (nanopass-case (Lsrc Expr) e
[(ref ,maybe-src ,x) #f]
[(quote ,d) #f]
[,pr #f]
[else (not (fld-mutable? (car fld*)))])
[else (not (if fld*
(fld-mutable? (car fld*))
(bitwise-bit-set? mpm (fx+ idx 1))))])
(let ([t (cp0-make-temp #f)])
(values (cons t liftmt*) (cons e liftme*) (cons (build-ref t) e*)))
(values liftmt* liftme* (cons e e*))))))))])
@ -1053,10 +1090,7 @@
[(record-ref ,rtd ,type ,index ,e) #f]
[(record-set! ,rtd ,type ,index ,e1 ,e2) #f]
[(record ,rtd ,rtd-expr ,e* ...)
(and (andmap (lambda (fld)
(and (not (fld-mutable? fld))
(eq? (filter-foreign-type (fld-type fld)) 'scheme-object)))
(rtd-flds rtd))
(and (rtd-all-immutable-scheme-objects? rtd)
(memoize (and (pure1? rtd-expr) (andmap pure1? e*))))]
[(set! ,maybe-src ,x ,e) #f]
[(record-cd ,rcd ,rtd-expr ,e) (memoize (pure1? e))]
@ -1115,12 +1149,12 @@
[(seq ,e1 ,e2) (memoize (and (ivory? e1) (ivory? e2)))]
[(record-ref ,rtd ,type ,index ,e)
; here ivory? differs from pure?
(and (not (fld-mutable? (list-ref (rtd-flds rtd) index)))
(and (rtd-immutable-field? rtd index)
(memoize (ivory1? e)))]
[(record-set! ,rtd ,type ,index ,e1 ,e2) #f]
[(record ,rtd ,rtd-expr ,e* ...)
; here ivory? differs from pure?
(and (andmap (lambda (fld) (not (fld-mutable? fld))) (rtd-flds rtd))
(and (rtd-all-immutable? rtd)
(memoize (and (ivory1? rtd-expr) (andmap ivory1? e*))))]
[(set! ,maybe-src ,x ,e) #f]
[(record-cd ,rcd ,rtd-expr ,e) (memoize (ivory1? e))]
@ -2998,6 +3032,13 @@
(nanopass-case (Lsrc Expr) (result-exp (value-visit-operand! ?fields))
[(quote ,d) (k d)]
[else #f]))
(define (get-mutability-mask ?mutability-mask k)
(cond
[(not ?mutability-mask) (k #f)]
[else
(nanopass-case (Lsrc Expr) (result-exp (value-visit-operand! ?mutability-mask))
[(quote ,d) (k d)]
[else #f])]))
(define (get-sealed x)
(nanopass-case (Lsrc Expr) (if x (result-exp (value-visit-operand! x)) false-rec)
[(quote ,d) (values (if d #t #f) ctrtd-sealed-known)]
@ -3061,7 +3102,7 @@
(mrt ?parent ?name ?fields ?sealed ?opaque ctxt level $make-record-type '$make-record-type
(list* ?base-id ?parent ?name ?fields ?sealed ?opaque ?extras))]))
(let ()
(define (mrtd ?parent ?uid ?fields ?sealed ?opaque ctxt level prim primname opnd*)
(define (mrtd ?parent ?uid ?fields ?mutability-mask ?sealed ?opaque ctxt level prim primname opnd*)
(or (nanopass-case (Lsrc Expr) (result-exp (value-visit-operand! ?uid))
[(quote ,d)
(and d
@ -3077,12 +3118,17 @@
(lambda (prtd)
(get-fields ?fields
(lambda (fields)
(get-mutability-mask ?mutability-mask
(lambda (mutability-mask)
(let-values ([(sealed? sealed-flag) (get-sealed ?sealed)]
[(opaque? opaque-flag) (get-opaque ?opaque prtd)])
(cond
[(guard (c [#t #f])
(if ?mutability-mask
($make-record-type-descriptor* base-ctrtd 'tmp prtd #f
sealed? opaque? fields mutability-mask 'cp0 (fxlogor sealed-flag opaque-flag))
($make-record-type-descriptor base-ctrtd 'tmp prtd #f
sealed? opaque? fields 'cp0 (fxlogor sealed-flag opaque-flag))) =>
sealed? opaque? fields 'cp0 (fxlogor sealed-flag opaque-flag)))) =>
(lambda (rtd)
(residualize-seq opnd* '() ctxt)
`(record-type ,rtd
@ -3090,19 +3136,31 @@
; ?base-rtd, ?name, ?uid, ?who, and ?extras
,(build-primcall (app-preinfo ctxt) level primname
(value-visit-operands! opnd*))))]
[else #f]))))))))
[else #f]))))))))))
(define-inline 2 make-record-type-descriptor
[(?name ?parent ?uid ?sealed ?opaque ?fields)
(mrtd ?parent ?uid ?fields ?sealed ?opaque ctxt level
(mrtd ?parent ?uid ?fields #f ?sealed ?opaque ctxt level
make-record-type-descriptor 'make-record-type-descriptor
(list ?name ?parent ?uid ?sealed ?opaque ?fields))])
(define-inline 2 make-record-type-descriptor*
[(?name ?parent ?uid ?sealed ?opaque ?fields ?mutability-mask)
(mrtd ?parent ?uid ?fields ?mutability-mask ?sealed ?opaque ctxt level
make-record-type-descriptor* 'make-record-type-descriptor*
(list ?name ?parent ?uid ?sealed ?opaque ?fields ?mutability-mask))])
(define-inline 2 $make-record-type-descriptor
[(?base-rtd ?name ?parent ?uid ?sealed ?opaque ?fields ?who . ?extras)
(mrtd ?parent ?uid ?fields ?sealed ?opaque ctxt level
(mrtd ?parent ?uid ?fields #f ?sealed ?opaque ctxt level
$make-record-type-descriptor '$make-record-type-descriptor
(list* ?base-rtd ?name ?parent ?uid ?sealed ?opaque ?fields ?who ?extras))])))
(list* ?base-rtd ?name ?parent ?uid ?sealed ?opaque ?fields ?who ?extras))])
(define-inline 2 $make-record-type-descriptor*
[(?base-rtd ?name ?parent ?uid ?sealed ?opaque ?fields ?mutability-mask ?who . ?extras)
(mrtd ?parent ?uid ?fields ?mutability-mask ?sealed ?opaque ctxt level
$make-record-type-descriptor* '$make-record-type-descriptor*
(list* ?base-rtd ?name ?parent ?uid ?sealed ?opaque ?fields ?mutability-mask ?who ?extras))])))
(let ()
; if you update this, also update duplicate in record.ss
(define-record-type rcd
@ -3282,7 +3340,14 @@
(let ()
(define (go safe? rtd rtd-e ctxt)
(let* ([fld* (rtd-flds rtd)]
(let* ([fld* (let ([flds (rtd-flds rtd)])
(cond
[(fixnum? flds)
(let loop ([i flds])
(if (fx= i 0)
'()
(cons (rtd-make-fld rtd i) (loop (fx- i 1)))))]
[else flds]))]
[t* (map (lambda (x) (cp0-make-temp #t)) fld*)]
[check* (if safe?
(fold-right
@ -3370,7 +3435,7 @@
(let f ([ctprcd (ctrcd-ctprcd ctrcd)] [crtd rtd] [prtd prtd] [vars '()])
(let ([pp-args (cp0-make-temp #f)]
[new-vars (map (lambda (x) (cp0-make-temp #f))
(vector->list (record-type-field-names crtd)))])
(vector->list (record-type-field-indices crtd)))])
(set-prelex-immutable-value! pp-args #t)
`(case-lambda ,(make-preinfo-lambda)
(clause (,pp-args) -1
@ -3393,14 +3458,14 @@
(f (ctrcd-ctprcd ctprcd) prtd pprtd vars))]
[else
(let ([new-vars (map (lambda (x) (cp0-make-temp #f))
(csv7:record-type-field-names prtd))])
(csv7:record-type-field-indices prtd))])
(build-lambda new-vars
`(call ,(app-preinfo ctxt) ,(go (< level 3) rtd rtd-e ctxt)
,(map build-ref (append new-vars vars))
...)))])))]
[else
(let ([new-vars (map (lambda (x) (cp0-make-temp #f))
(csv7:record-type-field-names prtd))])
(csv7:record-type-field-indices prtd))])
(build-lambda new-vars
`(call ,(app-preinfo ctxt) ,(go (< level 3) rtd rtd-e ctxt)
,(map build-ref (append new-vars vars)) ...)))])
@ -3440,7 +3505,7 @@
(nanopass-case (Lsrc Expr) (result-exp (value-visit-operand! ?field))
[(quote ,d)
(cond
[(symbol? d)
[(and (symbol? d) (not (fixnum? (rtd-flds rtd))))
; reverse order to check child's fields first
(let loop ([flds (reverse (rtd-flds rtd))] [index (length (rtd-flds rtd))])
(let ([index (fx- index 1)])
@ -3451,8 +3516,13 @@
(loop (cdr flds) index))))))]
[(fixnum? d)
(let ((flds (rtd-flds rtd)))
(cond
[(fixnum? flds)
(and ($fxu< d flds)
(k rtd-e rtd (rtd-make-fld rtd d) d))]
[else
(and ($fxu< d (length flds))
(k rtd-e rtd (list-ref flds d) d)))]
(k rtd-e rtd (list-ref flds d) d))]))]
[else #f])]
[else #f]))
@ -3460,9 +3530,15 @@
(nanopass-case (Lsrc Expr) (result-exp (value-visit-operand! ?field))
[(quote ,d)
(let ([flds (rtd-flds rtd)] [prtd (rtd-parent rtd)])
(let ([index (if prtd (+ d (length (rtd-flds prtd))) d)])
(let ([p-flds (and prtd (rtd-flds prtd))])
(let ([index (if prtd (+ d (if (fixnum? p-flds) p-flds (length p-flds))) d)])
(cond
[(fixnum? flds)
(and ($fxu< index flds)
(k rtd-e rtd (rtd-make-fld rtd index) index))]
[else
(and ($fxu< index (length flds))
(k rtd-e rtd (list-ref flds index) index))))]
(k rtd-e rtd (list-ref flds index) index))]))))]
[else #f]))
(define (find-rtd-and-field ?rtd ?field find-fld k)
@ -3746,7 +3822,18 @@
(list xval rtdval)))))))
(define obviously-incompatible?
(lambda (instance-rtd rtd)
(let f ([ls1 (rtd-flds instance-rtd)] [ls2 (rtd-flds rtd)])
(let ([flds1 (rtd-flds instance-rtd)]
[flds2 (rtd-flds rtd)])
(cond
[(or (fixnum? flds1) (fixnum? flds2))
(or (not (fixnum? flds1))
(not (fixnum? flds2))
(fx< flds1 flds2)
(not (= (rtd-mpm instance-rtd)
(bitwise-and (rtd-mpm rtd)
(sub1 (bitwise-arithmetic-shift-left 1 (fx+ flds1 1)))))))]
[else
(let f ([ls1 flds1] [ls2 flds2])
(if (null? ls2)
(if (record-type-parent instance-rtd)
; could work harder here, though it gets trickier (so not obvious)...
@ -3760,7 +3847,7 @@
(not (eq? (record-type-opaque? instance-rtd) (record-type-opaque? rtd))))))
(or (null? ls1)
(not (equal? (car ls1) (car ls2)))
(f (cdr ls1) (cdr ls2)))))))
(f (cdr ls1) (cdr ls2)))))]))))
(nanopass-case (Lsrc Expr) (result-exp rtdval)
[(quote ,d0)
(and (record-type-descriptor? d0)
@ -3898,7 +3985,7 @@
(nanopass-case (Lsrc Expr) (result-exp rtd-expr)
[(quote ,d)
(and (record-type-descriptor? d)
(if (andmap (lambda (fld) (not (fld-mutable? fld))) (rtd-flds d))
(if (rtd-all-immutable? d)
(let ([e* (objs-if-constant (value-visit-operands! ?e*))])
(and e*
(begin
@ -5063,10 +5150,7 @@
(or (nanopass-case (Lsrc Expr) (result-exp rtd-expr)
[(quote ,d)
(and (record-type-descriptor? d)
(andmap (lambda (fld)
(and (not (fld-mutable? fld))
(eq? (filter-foreign-type (fld-type fld)) 'scheme-object)))
(rtd-flds d))
(rtd-all-immutable-scheme-objects? d)
(let ([d* (objs-if-constant e*)])
(and d*
(make-1seq ctxt
@ -5110,7 +5194,7 @@
(nanopass-case (Lsrc Expr) (result-exp/indirect-ref e0)
[(record ,rtd1 ,rtd-expr ,e* ...)
(and (> (length e*) index)
(not (fld-mutable? (list-ref (rtd-flds rtd) index)))
(rtd-immutable-field? rtd index)
(let ([e (list-ref e* index)])
(and (nanopass-case (Lsrc Expr) e
[(quote ,d) #t]

View File

@ -44,8 +44,11 @@
(define record-field-offset
(lambda (rtd index)
(let ([rtd (maybe-remake-rtd rtd)])
(fld-byte (list-ref (rtd-flds rtd) index)))))
(let* ([rtd (maybe-remake-rtd rtd)]
[flds (rtd-flds rtd)])
(if (fixnum? flds)
(fx+ (constant record-data-disp) (fxsll index (constant log2-ptr-bytes)))
(fld-byte (list-ref flds index))))))
(define-pass cpcheck : Lsrc (ir) -> Lsrc ()
(definitions
@ -185,8 +188,10 @@
[(record ,rtd ,[rtd-expr #f -> rtd-expr] ,[e* #f -> e*] ...)
(let ([rtd (maybe-remake-rtd rtd)])
(let ([fld* (rtd-flds rtd)] [rec-t (make-prelex*)])
(safe-assert (fx= (length e*) (length fld*)))
(let ([filler* (fold-right
(safe-assert (fx= (length e*) (if (fixnum? fld*) fld* (length fld*))))
(let ([filler* (if (fixnum? fld*)
'()
(fold-right
(lambda (fld e filler*)
(let ([type (fld-type fld)])
(if (eq? (filter-foreign-type type) 'scheme-object)
@ -195,7 +200,7 @@
`(call ,(make-preinfo-call) ,(lookup-primref 3 '$object-set!)
(quote ,type) (ref #f ,rec-t) (quote ,(fld-byte fld)) ,e)
filler*))))
'() fld* e*)])
'() fld* e*))])
(if (null? filler*)
`(call ,(make-preinfo-call) ,(lookup-primref 3 '$record) ,rtd-expr ,e* ...)
(begin

View File

@ -56,6 +56,7 @@ Handling letrec and letrec*
(include "base-lang.ss")
(define rtd-flds (csv7:record-field-accessor #!base-rtd 'flds))
(define rtd-mpm (csv7:record-field-accessor #!base-rtd 'mpm))
(define-pass lift-profile-forms : Lsrc (ir) -> Lsrc ()
(definitions
@ -370,11 +371,16 @@ Handling letrec and letrec*
(values
`(record ,rtd ,rtd-expr ,e* ...)
(and (and rtd-pure? pure?)
(let ([flds (rtd-flds rtd)])
(cond
[(fixnum? flds)
(eqv? 0 (rtd-mpm rtd))]
[else
(andmap
(lambda (fld)
(and (not (fld-mutable? fld))
(eq? (filter-foreign-type (fld-type fld)) 'scheme-object)))
(rtd-flds rtd)))))]
flds)])))))]
[(record-type ,rtd ,e) (Expr e)]
[(record-cd ,rcd ,rtd-expr ,e) (Expr e)]
[(immutable-list (,[e* pure?*] ...) ,[e pure?])

View File

@ -85,10 +85,16 @@
(lambda (x t a? d)
(let ([rtd ($record-type-descriptor x)])
(bld rtd t a? d)
(do ([flds (rtd-flds rtd) (cdr flds)] [i 0 (+ i 1)])
(let ([flds (rtd-flds rtd)])
(if (fixnum? flds)
(let loop ([i 0])
(unless (fx= i flds)
(bld ($record-ref x i) t a? d)
(loop (fx+ i 1))))
(do ([flds flds (cdr flds)] [i 0 (+ i 1)])
((null? flds))
(when (memq (fld-type (car flds)) '(scheme-object ptr))
(bld ((csv7:record-field-accessor rtd i) x) t a? d))))))
(bld ((csv7:record-field-accessor rtd i) x) t a? d))))))))
(define bld-ht
(lambda (x t a? d)
@ -385,7 +391,7 @@
[else ($oops 'fasl-write "unexpected difference in filtered foreign type ~s for unfiltered type ~s" filtered-type type)])
($oops 'fasl-write "host value ~s for type ~s is too big for target" val type))))))
(define put-field
(lambda (target-fld pad val)
(lambda (field-type field-addr pad val)
(define put-i64
(lambda (p val)
(constant-case ptr-bits
@ -395,7 +401,7 @@
(syntax-rules ()
[(_ fasl-fld-type)
(put-u8 p (fxlogor (fxsll pad 4) (constant fasl-fld-type)))]))
(let ([type (fld-type target-fld)] [addr (fld-byte target-fld)])
(let ([type field-type] [addr field-addr])
; using filter-foreign-type to get target filtering
(case (filter-foreign-type type)
[(scheme-object) (put-padty fasl-fld-ptr) (wrf val p t a?) (constant ptr-bytes)]
@ -433,17 +439,23 @@
[target-rtd (maybe-remake-rtd host-rtd)]
[target-fld* (rtd-flds target-rtd)])
(put-uptr p (rtd-size target-rtd))
(put-uptr p (length target-fld*))
(put-uptr p (if (fixnum? target-fld*) target-fld* (length target-fld*)))
(wrf host-rtd p t a?)
(if (fixnum? target-fld*)
(let loop ([i 0] [addr (constant record-data-disp)])
(unless (fx= i target-fld*)
(let ([sz (put-field 'scheme-object addr 0 ($record-ref x i))])
(loop (fx+ i 1) (fx+ addr sz)))))
(fold-left
(lambda (last-target-addr host-fld target-fld)
(let ([val (get-field host-fld)])
(check-field target-fld val)
(let ([target-addr (fld-byte target-fld)])
(fx+ target-addr (put-field host-fld (fx- target-addr last-target-addr) val)))))
(fx+ target-addr (put-field (fld-type host-fld) (fld-byte host-fld)
(fx- target-addr last-target-addr) val)))))
(constant record-data-disp)
(rtd-flds host-rtd)
target-fld*))))
target-fld*)))))
(define wrf-record
(lambda (x p t a?)

View File

@ -2061,7 +2061,9 @@
(define make-record-object
(lambda (x)
(let* ((rtd ($record-type-descriptor x))
(fields (csv7:record-type-field-names rtd)))
(fields (if (record-type-named-fields? rtd)
(csv7:record-type-field-names rtd)
(csv7:record-type-field-indices rtd))))
(define check-field
(lambda (f)
(unless (or (and (symbol? f) (memq f fields))
@ -2644,12 +2646,21 @@
((fx= i n) size)))]
[($record? x)
(let ([rtd ($record-type-descriptor x)])
(let ([flds (rtd-flds rtd)])
(cond
[(fixnum? flds)
(let loop ([i 0] [size 0])
(cond
[(fx= i flds) size]
[else (loop (fx+ i 1)
(fx+ size (compute-size ($record-ref x i))))]))]
[else
(fold-left (lambda (size fld)
(if (eq? (fld-type fld) 'scheme-object)
(fx+ size (compute-size ($object-ref 'scheme-object x (fld-byte fld))))
size))
(fx+ (align (rtd-size rtd)) (compute-size rtd))
(rtd-flds rtd)))]
flds)])))]
[(string? x) (align (fx+ (constant header-size-string) (fx* (string-length x) (constant string-char-bytes))))]
[(box? x) (fx+ (constant size-box) (compute-size (unbox x)))]
[(flonum? x) (constant size-flonum)]
@ -2838,10 +2849,18 @@
(set-cdr! p (fx+ (cdr p) size)))
(eq-hashtable-set! rtd-ht rtd (cons 1 size))))
(compute-composition! rtd)
(let ([flds (rtd-flds rtd)])
(cond
[(fixnum? flds)
(let loop ([i 0])
(unless (fx= i flds)
(compute-composition! ($record-ref x i))
(loop (fx+ i 1))))]
[else
(for-each (lambda (fld)
(when (eq? (fld-type fld) 'scheme-object)
(compute-composition! ($object-ref 'scheme-object x (fld-byte fld)))))
(rtd-flds rtd)))]
(rtd-flds rtd))])))]
[(string? x) (incr! string (align (fx+ (constant header-size-string) (fx* (string-length x) (constant string-char-bytes)))))]
[(box? x)
(incr! box (constant size-box))
@ -2990,13 +3009,21 @@
[($record? x)
(let ([rtd ($record-type-descriptor x)])
(construct-proc rtd
(let ([flds (rtd-flds rtd)])
(cond
[(fixnum? flds)
(let loop ([i 0])
(if (fx= i flds)
next-proc
(construct-proc ($record-ref x i) (loop (fx+ i 1)))))]
[else
(let f ([flds (rtd-flds rtd)])
(if (null? flds)
next-proc
(let ([fld (car flds)])
(if (eq? (fld-type fld) 'scheme-object)
(construct-proc ($object-ref 'scheme-object x (fld-byte fld)) (f (cdr flds)))
(f (cdr flds))))))))]
(f (cdr flds))))))]))))]
[(or (fxvector? x) (bytevector? x) (string? x) (flonum? x) (bignum? x)
($inexactnum? x) ($rtd-counts? x) (phantom-bytevector? x))
next-proc]

View File

@ -16,7 +16,11 @@
(define compute-field-offsets
; type-disp is the offset from the ptr to the object's true address
; ls is a list of field descriptors
(lambda (who type-disp ls)
(case-lambda
[(who type-disp n mpm)
;; Simple case: all pointers, mutability mask given
(values -1 mpm n (fx* n (constant ptr-bytes)))]
[(who type-disp ls)
(define parse-field
(lambda (f)
(define supported-type
@ -107,5 +111,4 @@
(if (= (- (ash 1 (quotient (+ size -1 (constant ptr-bytes)) (constant ptr-bytes))) 1) m)
-1
m)))
(values (sanitize-mask pm size) mpm flds size)))))
(values (sanitize-mask pm size) mpm flds size)))]))

View File

@ -845,6 +845,7 @@
((csv7: record-type-descriptor) [sig [(record) -> (rtd)]] [flags pure mifoldable discard true cp02])
((csv7: record-type-field-decls) [sig [(rtd) -> (list)]] [flags pure mifoldable discard true cp02])
((csv7: record-type-field-names) [sig [(rtd) -> (list)]] [flags pure mifoldable discard true cp02])
((csv7: record-type-field-indices) [sig [(rtd) -> (list)]] [flags pure mifoldable discard true])
((csv7: record-type-name) [sig [(rtd) -> (string)]] [flags pure mifoldable discard true cp02])
((csv7: record-type-symbol) [sig [(rtd) -> (symbol)]] [flags pure mifoldable discard true cp02])
)
@ -1476,6 +1477,7 @@
(make-phantom-bytevector [sig [(uptr) -> (phantom-bytevector)]] [flags true])
(make-pseudo-random-generator [sig [() -> (pseudo-random-generator)]] [flags true])
(make-record-type [sig [(sub-ptr sub-list) (maybe-rtd sub-ptr sub-list) -> (rtd)]] [flags pure alloc cp02])
(make-record-type-descriptor* [sig [(symbol maybe-rtd maybe-symbol ptr ptr fixnum exact-integer) -> (rtd)]] [flags pure alloc cp02])
(make-source-condition [sig [(ptr) -> (condition)]] [flags pure unrestricted mifoldable discard])
(make-source-file-descriptor [sig [(string binary-input-port) (string binary-input-port ptr) (string binary-input-port ptr ptr) -> (sfd)]] [flags true])
(make-source-object [sig [(sfd uint uint) (sfd uint uint uint uint) -> (source-object)]] [flags pure true mifoldable discard])
@ -1588,6 +1590,8 @@
(record-reader [sig [(sub-ptr) -> (ptr)] [(sub-ptr sub-ptr) -> (void)]] [flags])
(record-type-equal-procedure [sig [(rtd) -> (maybe-procedure)] [(rtd maybe-procedure) -> (void)]] [flags])
(record-type-hash-procedure [sig [(rtd) -> (maybe-procedure)] [(rtd maybe-procedure) -> (void)]] [flags])
(record-type-field-indices [sig [(rtd) -> (vector)]] [flags])
(record-type-named-fields? [sig [(rtd) -> (boolean)]] [flags])
(record-writer [sig [(rtd) -> (maybe-procedure)] [(rtd maybe-procedure) -> (void)]] [flags])
(register-signal-handler [sig [(sint procedure) -> (void)]] [flags])
(remove-foreign-entry [sig [(string) -> (void)]] [flags true])
@ -2170,6 +2174,7 @@
($make-recompile-condition [flags single-valued])
($make-record-constructor-descriptor [flags single-valued pure true cp02])
($make-record-type-descriptor [flags single-valued pure alloc cp02])
($make-record-type-descriptor* [flags single-valued pure alloc cp02])
($make-record-type [sig [(rtd maybe-rtd sub-ptr sub-list ptr ptr ptr ...) -> (rtd)]] [flags pure alloc cp02])
($make-relocation-table! [flags single-valued])
($make-rnrs-libraries [flags single-valued])

View File

@ -49,7 +49,7 @@
; we use write instead of wr here so that the field doesn't get
; a reference (#n#) when print-graph is true.
(write (or (record-reader rtd) (record-type-uid rtd)) p)
(do ([flds (csv7:record-type-field-names rtd) (cdr flds)]
(do ([flds (csv7:record-type-field-indices rtd) (cdr flds)]
[i 0 (+ i 1)])
((null? flds))
(write-char #\space p)

View File

@ -1110,7 +1110,7 @@
(rd-fix-graph (vector-ref x m) rd-set-vector-tail! x m))))]
[($record? x)
(let ((d ($record-type-descriptor x)))
(do ([fields (csv7:record-type-field-names d) (cdr fields)]
(do ([fields (csv7:record-type-field-indices d) (cdr fields)]
[i 0 (+ i 1)])
((null? fields))
(when (csv7:record-field-accessible? d i)
@ -1134,7 +1134,7 @@
(let* ((dr (car wl))
(rtd (delayed-record-rtd dr))
(vals (delayed-record-vals dr))
(fields (csv7:record-type-field-names rtd)))
(fields (csv7:record-type-field-indices rtd)))
(if (andmap
(lambda (f v)
(or (not (delayed-record? v))

View File

@ -38,9 +38,19 @@
(define (child-flds rtd)
(let ([flds (rtd-flds rtd)] [prtd (rtd-parent rtd)])
(if prtd
(list-tail flds (length (rtd-flds prtd)))
(let ([p-flds (rtd-flds prtd)])
(if (fixnum? flds)
(fx- flds p-flds)
(list-tail flds (length p-flds))))
flds)))
;; assumes anonymous fields
(define (parent-flds rtd)
(let ([prtd (rtd-parent rtd)])
(if prtd
(rtd-flds prtd)
0)))
; $record is hand-coded and is defined in prims.ss
(let ([addr? (constant-case ptr-bits
@ -403,21 +413,41 @@
(constant rtd-opaque)
0)
(if sealed? (constant rtd-sealed) 0)))
(define ($mrt who base-rtd name parent uid flags fields extras)
(define ($mrt who base-rtd name parent uid flags fields mutability-mask extras)
(include "layout.ss")
(when (and parent (record-type-sealed? parent))
(when parent
(when (record-type-sealed? parent)
($oops who "cannot extend sealed record type ~s" parent))
(let ([parent-fields (if (not parent) '() (csv7:record-type-field-decls parent))]
[uid (or uid ((current-generate-id) name))])
(if (fixnum? fields)
(unless (fixnum? (rtd-flds parent))
($oops who "cannot make anonymous-field record type ~s from named-field parent record type ~s" name parent))
(when (fixnum? (rtd-flds parent))
($oops who "cannot make named-field record type ~s from anonymous-field parent record type ~s" name parent))))
(let ([uid (or uid ((current-generate-id) name))])
; start base offset at rtd field
; synchronize with syntax.ss and front.ss
(let-values ([(pm mpm flds size)
(if (fixnum? fields)
(let ([parent-n (if parent
(let ([p-flds (rtd-flds parent)])
(if (fixnum? p-flds)
p-flds
(length p-flds)))
0)])
(unless (< (+ fields parent-n 1) (fxsrl (most-positive-fixnum) (constant log2-ptr-bytes)))
($oops who "cannot make record type with ~s fields" (+ fields parent-n)))
(compute-field-offsets who
(constant record-type-disp)
(fx+ parent-n fields 1)
(+ (bitwise-arithmetic-shift-left mutability-mask (fx+ parent-n 1))
(if parent (rtd-mpm parent) 0))))
(let ([parent-fields (if (not parent) '() (csv7:record-type-field-decls parent))])
(compute-field-offsets who
(constant record-type-disp)
; rtd must be immutable if we are ever to store records
; in space pure
(cons `(immutable scheme-object ,uid)
(append parent-fields fields)))])
(append parent-fields fields)))))])
(cond
[(and (not (fxlogtest flags (constant rtd-generative)))
(let ([x ($sgetprop uid '*rtd* #f)])
@ -436,21 +466,23 @@
; following is paranoid; overall size
; check should suffice
#;(= (fld-byte fld1) (fld-byte fld2)))))
(and (= (length flds1) (length flds2))
(andmap same-field? flds1 flds2))))
(or (and (fixnum? flds1) (fixnum? flds2) (fx= flds1 flds2))
(and (not (fixnum? flds1)) (not (fixnum? flds2))
(fx= (length flds1) (length flds2))
(andmap same-field? flds1 flds2)))))
; following assumes extras match
(let ()
(define (squawk what) ($oops who "incompatible record type ~s - ~a" name what))
(unless (eq? ($record-type-descriptor rtd) base-rtd) (squawk "different base rtd"))
(unless (eq? (rtd-parent rtd) parent) (squawk "different parent"))
(unless (same-fields? (rtd-flds rtd) (cdr flds)) (squawk "different fields"))
(unless (same-fields? (rtd-flds rtd) (if (pair? flds) (cdr flds) (fx- flds 1))) (squawk "different fields"))
(unless (= (rtd-mpm rtd) mpm) (squawk "different mutability"))
(unless (fx= (rtd-flags rtd) flags) (squawk "different flags"))
(unless (eq? (rtd-size rtd) size) (squawk "different size")))
rtd)]
[else
(let ([rtd (apply #%$record base-rtd parent size pm mpm name
(cdr flds) flags uid #f extras)])
(if (pair? flds) (cdr flds) (fx- flds 1)) flags uid #f extras)])
(with-tc-mutex ($sputprop uid '*rtd* rtd))
rtd)]))))
@ -463,12 +495,18 @@
[parent (rtd-parent rtd)]
[name (rtd-name rtd)]
[flags (rtd-flags rtd)]
[fields (csv7:record-type-field-decls rtd)])
[flds (rtd-flds rtd)])
(let-values ([(pm mpm flds size)
(if (fixnum? flds)
(compute-field-offsets who
(constant record-type-disp)
(cons `(immutable scheme-object ,uid) fields))])
(let ([rtd (apply #%$record base-rtd parent size pm mpm name (cdr flds) flags uid #f
(fx+ flds 1) (rtd-mpm rtd))
(let ([fields (csv7:record-type-field-decls rtd)])
(compute-field-offsets who
(constant record-type-disp)
(cons `(immutable scheme-object ,uid) fields))))])
(let ([rtd (apply #%$record base-rtd parent size pm mpm name
(if (pair? flds) (cdr flds) (fx- flds 1)) flags uid #f
(let* ([n (length (rtd-flds ($record-type-descriptor base-rtd)))]
[ls (list-tail (rtd-flds base-rtd) n)])
(let f ([n n] [ls ls])
@ -486,12 +524,12 @@
($mrt 'make-record-type base-rtd
(string->symbol (symbol->string name)) parent name
(make-flags name sealed? opaque? parent)
fields extras)]
fields 0 extras)]
[(string? name)
($mrt 'make-record-type base-rtd
(string->symbol name) parent #f
(make-flags #f sealed? opaque? parent)
fields extras)]
fields 0 extras)]
[else ($oops 'make-record-type "invalid record name ~s" name)]))
(set-who! make-record-type
@ -522,17 +560,28 @@
(mrt base-rtd parent name fields sealed? opaque? extras))))
(let ()
(define (mrtd base-rtd name parent uid sealed? opaque? fields who extras)
(define (mrtd base-rtd name parent uid sealed? opaque? fields mutability-mask? mutability-mask who extras)
(unless (symbol? name)
($oops who "invalid record name ~s" name))
(unless (or (not parent) (record-type-descriptor? parent))
($oops who "invalid parent ~s" parent))
(unless (or (not uid) (symbol? uid))
($oops who "invalid uid ~s" uid))
(cond
[mutability-mask?
(unless (and (fixnum? fields)
(fx>= fields 0))
($oops who "invalid field count ~s" fields))
(unless (and (or (fixnum? mutability-mask) (bignum? mutability-mask))
(eqv? 0 (bitwise-arithmetic-shift-right mutability-mask fields)))
($oops who "invalid mutability mask ~s for field count ~s" mutability-mask fields))]
[else
(unless (vector? fields)
($oops who "invalid field vector ~s" fields))
($oops who "invalid field vector ~s" fields))])
($mrt who base-rtd name parent uid
(make-flags uid sealed? opaque? parent)
(if mutability-mask?
fields
(let ([n (vector-length fields)])
(let f ([i 0])
(if (fx= i n)
@ -545,18 +594,33 @@
(symbol? (car x))
(null? (cdr x)))))
($oops who "invalid field specifier ~s" x))
(cons x (f (fx+ i 1)))))))
(cons x (f (fx+ i 1))))))))
mutability-mask
extras))
(set! $make-record-type-descriptor
(lambda (base-rtd name parent uid sealed? opaque? fields who . extras)
(case-lambda
[(base-rtd name parent uid sealed? opaque? fields who . extras)
(unless (record-type-descriptor? base-rtd)
($oops who "invalid base rtd ~s" base-rtd))
(mrtd base-rtd name parent uid sealed? opaque? fields who extras)))
(mrtd base-rtd name parent uid sealed? opaque? fields #f 0 who extras)]))
(set! $make-record-type-descriptor*
(case-lambda
[(base-rtd name parent uid sealed? opaque? fields mutability-mask who . extras)
(unless (record-type-descriptor? base-rtd)
($oops who "invalid base rtd ~s" base-rtd))
(mrtd base-rtd name parent uid sealed? opaque? fields #t mutability-mask who extras)]))
(set-who! make-record-type-descriptor
(lambda (name parent uid sealed? opaque? fields)
(mrtd base-rtd name parent uid sealed? opaque? fields who '()))))
(case-lambda
[(name parent uid sealed? opaque? fields)
(mrtd base-rtd name parent uid sealed? opaque? fields #f 0 who '())]))
(set-who! make-record-type-descriptor*
(case-lambda
[(name parent uid sealed? opaque? fields mutability-mask)
(mrtd base-rtd name parent uid sealed? opaque? fields #t mutability-mask who '())])))
(set! record-type-descriptor?
(lambda (x)
@ -605,33 +669,79 @@
($oops who "~s is not a record type descriptor" rtd))
(rtd-uid rtd)))
(set-who! record-type-named-fields?
(lambda (rtd)
(unless (record-type-descriptor? rtd)
($oops who "~s is not a record type descriptor" rtd))
(not (fixnum? (rtd-flds rtd)))))
(set-who! #(csv7: record-type-field-names)
(lambda (rtd)
(unless (record-type-descriptor? rtd)
($oops who "~s is not a record type descriptor" rtd))
(map (lambda (x) (fld-name x)) (rtd-flds rtd))))
(let ([flds (rtd-flds rtd)])
(if (fixnum? flds)
($oops who "~s is a record type descriptor with anonymous fields" rtd)
(map (lambda (x) (fld-name x)) flds)))))
(set-who! record-type-field-names
(lambda (rtd)
(unless (record-type-descriptor? rtd)
($oops who "~s is not a record type descriptor" rtd))
(list->vector (map (lambda (x) (fld-name x)) (child-flds rtd)))))
(let ([flds (child-flds rtd)])
(if (fixnum? flds)
($oops who "~s is a record type descriptor with anonymous fields" rtd)
(list->vector (map (lambda (x) (fld-name x)) flds))))))
(set-who! #(csv7: record-type-field-indices)
(lambda (rtd)
(unless (record-type-descriptor? rtd)
($oops who "~s is not a record type descriptor" rtd))
(let* ([flds (rtd-flds rtd)]
[n-flds (if (fixnum? flds)
flds
(length flds))])
(iota n-flds))))
(set-who! record-type-field-indices
(lambda (rtd)
(unless (record-type-descriptor? rtd)
($oops who "~s is not a record type descriptor" rtd))
(let* ([flds (rtd-flds rtd)]
[n-flds (let ([prtd (rtd-parent rtd)])
(if (fixnum? flds)
(fx- flds (if prtd (rtd-flds prtd) 0))
(fx- (length flds) (if prtd (length (rtd-flds prtd)) 0))))])
(list->vector (iota n-flds)))))
(set-who! #(csv7: record-type-field-decls)
(lambda (rtd)
(unless (record-type-descriptor? rtd)
($oops who "~s is not a record type descriptor" rtd))
(let ([flds (rtd-flds rtd)])
(if (fixnum? flds)
(let loop ([flds flds])
(if (fx= 0 flds)
'()
(cons '(mutable scheme-object unknown) (loop (fx- flds 1)))))
(map (lambda (x)
`(,(if (fld-mutable? x) 'mutable 'immutable)
,(fld-type x)
,(fld-name x)))
(rtd-flds rtd))))
flds)))))
(set! $record-type-field-offsets
(lambda (rtd)
(unless (record-type-descriptor? rtd)
($oops '$record-type-field-offsets "~s is not a record type descriptor" rtd))
(map (lambda (x) (fld-byte x)) (rtd-flds rtd))))
(let ([flds (rtd-flds rtd)])
(if (fixnum? flds)
(let loop ([i flds])
(if (fx= i flds)
'()
(cons (fx+ (constant record-data-disp) (fx* i (constant ptr-bytes)))
(loop (fx+ i 1)))))
(map (lambda (x) (fld-byte x)) (rtd-flds rtd))))))
(set! record-type-opaque?
(lambda (rtd)
@ -652,13 +762,21 @@
(#3%record-type-generative? rtd)))
(let ()
(define (make-default-fld field-spec mpm)
(make-fld 'unknown
(bitwise-bit-set? mpm (fx+ field-spec 1))
'scheme-object
(fx+ (constant record-data-disp) (fx* field-spec (constant ptr-bytes)))))
(define (find-fld who rtd field-spec)
(unless (record-type-descriptor? rtd)
($oops who "~s is not a record type descriptor" rtd))
(cond
[(symbol? field-spec)
; reverse order to check child's fields first
(let loop ((flds (reverse (rtd-flds rtd))))
(let loop ((flds (let ([flds (rtd-flds rtd)])
(if (fixnum? flds)
'()
(reverse flds)))))
(when (null? flds)
($oops who "unrecognized field name ~s for type ~s"
field-spec rtd))
@ -667,11 +785,14 @@
fld
(loop (cdr flds)))))]
[(and (fixnum? field-spec) (fx>= field-spec 0))
(let ((flds (rtd-flds rtd)))
(when (fx>= field-spec (length flds))
(let* ((flds (rtd-flds rtd))
(n-flds (if (fixnum? flds) flds (length flds))))
(when (fx>= field-spec n-flds)
($oops who "invalid field ordinal ~s for type ~s"
field-spec rtd))
(list-ref flds field-spec))]
(if (fixnum? flds)
(make-default-fld field-spec (rtd-mpm rtd))
(list-ref flds field-spec)))]
[else ($oops who "invalid field specifier ~s" field-spec)]))
(define (r6rs:find-fld who rtd field-spec)
@ -679,11 +800,14 @@
($oops who "~s is not a record type descriptor" rtd))
(cond
[(and (fixnum? field-spec) (fx>= field-spec 0))
(let ((flds (child-flds rtd)))
(when (fx>= field-spec (length flds))
(let* ((flds (child-flds rtd))
(n-flds (if (fixnum? flds) flds (length flds))))
(when (fx>= field-spec n-flds)
($oops who "invalid field index ~s for type ~s"
field-spec rtd))
(list-ref flds field-spec))]
(if (fixnum? flds)
(make-default-fld (fx+ field-spec (parent-flds rtd)) (rtd-mpm rtd))
(list-ref flds field-spec)))]
[else ($oops who "invalid field specifier ~s" field-spec)]))
(let ()
@ -747,7 +871,18 @@
(set-who! #(csv7: record-field-mutable?)
(lambda (rtd field-spec)
(fld-mutable? (find-fld who rtd field-spec))))
(cond
[(and (fixnum? field-spec)
(record-type-descriptor? rtd))
;; Try fast path
(let ([flds (rtd-flds rtd)])
(cond
[(and (fixnum? flds)
($fxu< field-spec flds))
(bitwise-bit-set? (rtd-mpm rtd) (fx+ field-spec 1))]
[else
(fld-mutable? (find-fld who rtd field-spec))]))]
[else (fld-mutable? (find-fld who rtd field-spec))])))
(set-who! record-field-mutable?
(lambda (rtd field-spec)
@ -804,7 +939,7 @@
(syntax-rules () ((_ type bytes pred) 'pred)))
(record-datatype cases ty ->pred
($oops 'record-constructor "unrecognized type ~s" ty))))
(let* ((flds (rtd-flds rtd)) (nflds (length flds)))
(let* ((flds (rtd-flds rtd)) (nflds (if (fixnum? flds) flds (length flds))))
(if (eqv? (rtd-pm rtd) -1) ; all pointers?
(let ()
(define-syntax nlambda
@ -832,6 +967,7 @@
($oops #f "incorrect number of arguments to ~s" constructor))
(apply $record rtd xr))
(ash 1 nflds)))]))
;; In this case, `flds` will be a list
(let* ([args (make-record-call-args flds (rtd-size rtd)
(map (lambda (x) 0) flds))]
[nargs (length args)]