M: fake-cpu gc-root-offset ;
-[ ] [
- [
- init-relocation
- init-gc-maps
+[
+ init-relocation
+ init-gc-maps
- 50 <byte-array> %
+ 50 <byte-array> %
- <gc-map> gc-map-here
+ <gc-map> gc-map-here
- 50 <byte-array> %
+ 50 <byte-array> %
+ T{ gc-map
+ { scrub-d { 0 1 1 1 0 } }
+ { scrub-r { 1 0 } }
+ { gc-roots V{ 1 3 } }
+ { derived-roots V{ { 2 4 } } }
+ } gc-map-here
+ emit-gc-maps
+] B{ } make
+"result" set
+
+[ 0 ] [ "result" get length 16 mod ] unit-test
+
+[
+ 100 <byte-array> %
+
+ ! The below data is 46 bytes -- 14 bytes padding needed to
+ ! align
+ 14 <byte-array> %
+
+ ! Bitmap - 2 bytes
+ ?{
+ ! scrub-d
+ t f f f t
+ ! scrub-r
+ f t
+ ! gc-roots
+ f t f t
+ } underlying>> %
+
+ ! Derived pointers
+ uint-array{ -1 -1 4 } underlying>> %
+
+ ! Return addresses
+ uint-array{ 100 } underlying>> %
+
+ ! GC info footer - 28 bytes
+ S{ gc-info
+ { scrub-d-count 5 }
+ { scrub-r-count 2 }
+ { check-d-count 0 }
+ { check-r-count 0 }
+ { gc-root-count 4 }
+ { derived-root-count 3 }
+ { return-address-count 1 }
+ } (underlying)>> %
+] B{ } make
+"expect" set
+
+[ t ] [ "result" get length "expect" get length = ] unit-test
+[ t ] [ "result" get "expect" get = ] unit-test
+
+! gc-map-needed?
+{ t t } [
+ T{ gc-map { scrub-d { 0 1 1 1 0 } } { scrub-r { 1 0 } } } gc-map-needed?
+ T{ gc-map { check-d { 0 1 1 1 } } } gc-map-needed?
+] unit-test
+
+! emit-scrub
+{ 3 V{ t t t f f f } } [
+ [ { { 0 0 0 } { 1 1 1 } } emit-scrub ] V{ } make
+] unit-test
+
+! emit-gc-info-bitmaps
+{
+ { 4 2 0 0 0 }
+ V{ 1 }
+} [
+ { T{ gc-map { scrub-d { 0 1 1 1 } } { scrub-r { 1 1 } } } } gc-maps set
+ [ emit-gc-info-bitmaps ] V{ } make
+] unit-test
+
+{
+ { 1 0 1 0 0 }
+ V{ 3 }
+} [
+ { T{ gc-map { scrub-d { 0 } } { check-d { 0 } } } } gc-maps set
+ [ emit-gc-info-bitmaps ] V{ } make
+] unit-test
+
+! derived-root-offsets
+USING: present prettyprint ;
+{
+ V{ { 2 4 } }
+} [
+ T{ gc-map { derived-roots V{ { 2 4 } } } }
+ derived-root-offsets
+] unit-test
+
+! emit-base-tables
+{
+ 3 B{ 255 255 255 255 255 255 255 255 4 0 0 0 }
+} [
+ { T{ gc-map { derived-roots V{ { 2 4 } } } } } gc-maps set
+ [ emit-base-tables ] B{ } make
+] unit-test
+
+
+! serialize-gc-maps
+{
+ B{ 0 0 0 0 }
+} [
+ { } return-addresses set serialize-gc-maps
+] unit-test
+
+{
+ B{
+ 17 123 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 0 0 0
+ }
+} [
+ { 123 } return-addresses set
+ { T{ gc-map { scrub-d { 0 1 1 1 0 } } } } gc-maps set
+ serialize-gc-maps
+] unit-test
+
+! gc-info + ret-addr + 9bits (5+2+2) = 28 + 4 + 2 = 34
+{ 34 } [
+ {
T{ gc-map
{ scrub-d { 0 1 1 1 0 } }
{ scrub-r { 1 0 } }
{ gc-roots V{ 1 3 } }
- { derived-roots V{ { 2 4 } } }
- } gc-map-here
- emit-gc-maps
- ] B{ } make
- "result" set
+ }
+ } gc-maps set
+ { 123 } return-addresses set
+ serialize-gc-maps length
] unit-test
-[ 0 ] [ "result" get length 16 mod ] unit-test
-
-[ ] [
- [
- 100 <byte-array> %
-
- ! The below data is 22 bytes -- 6 bytes padding needed to
- ! align
- 6 <byte-array> %
-
- ! Bitmap - 2 bytes
- ?{
- ! scrub-d
- t f f f t
- ! scrub-r
- f t
- ! gc-roots
- f t f t
- } underlying>> %
-
- ! Derived pointers
- uint-array{ -1 -1 4 } underlying>> %
-
- ! Return addresses
- uint-array{ 100 } underlying>> %
-
- ! GC info footer - 20 bytes
- S{ gc-info
- { scrub-d-count 5 }
- { scrub-r-count 2 }
- { gc-root-count 4 }
- { derived-root-count 3 }
- { return-address-count 1 }
- } (underlying)>> %
- ] B{ } make
- "expect" set
+! gc-info + ret-addr + 3 base-pointers + 9bits = 28 + 4 + 12 + 2 = 46
+{ 46 } [
+ {
+ T{ gc-map
+ { scrub-d { 0 1 1 1 0 } }
+ { scrub-r { 1 0 } }
+ { gc-roots V{ 1 3 } }
+ { derived-roots V{ { 2 4 } } }
+ }
+ } gc-maps set
+ { 123 } return-addresses set
+ serialize-gc-maps length
] unit-test
-
-[ ] [ "result" get length "expect" get length assert= ] unit-test
-[ ] [ "result" get "expect" get assert= ] unit-test
! Copyright (C) 2011 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs bit-arrays combinators
+USING: accessors arrays assocs bit-arrays classes.tuple combinators
combinators.short-circuit compiler.cfg.instructions
compiler.codegen.relocation cpu.architecture fry kernel layouts
-make math math.order namespaces sequences ;
+make math math.order namespaces sequences sequences.generalizations ;
IN: compiler.codegen.gc-maps
-! GC maps
+! GC maps
! Every code block either ends with
!
! uint[] <return addresses>
! uint <largest scrubbed data stack location>
! uint <largest scrubbed retain stack location>
+! uint <largest checked data stack location>
+! uint <largest checked retain stack location>
! uint <largest GC root spill slot>
! uint <largest derived root spill slot>
! int <number of return addresses>
SYMBOLS: return-addresses gc-maps ;
+
: gc-map-needed? ( gc-map -- ? )
- ! If there are no stack locations to scrub and no GC roots,
- ! there's no point storing the GC map.
- dup [
- {
- [ scrub-d>> empty? ]
- [ scrub-r>> empty? ]
- [ gc-roots>> empty? ]
- [ derived-roots>> empty? ]
- } 1&& not
- ] when ;
+ ! If there are no stack locations to scrub or check, and no GC
+ ! roots, there's no point storing the GC map.
+ tuple-slots [ empty? ] all? not ;
: gc-map-here ( gc-map -- )
dup gc-map-needed? [
: gc-root-offsets ( gc-map -- offsets )
gc-roots>> [ gc-root-offset ] map ;
-: emit-gc-info-bitmaps ( -- scrub-d-count scrub-r-count gc-root-count )
+: emit-gc-info-bitmaps ( -- scrub-and-check-counts )
[
gc-maps get {
[ [ scrub-d>> ] map emit-scrub ]
[ [ scrub-r>> ] map emit-scrub ]
+ [ [ check-d>> ] map emit-scrub ]
+ [ [ check-r>> ] map emit-scrub ]
[ [ gc-root-offsets ] map emit-gc-roots ]
- } cleave
+ } cleave 5 narray
] ?{ } make underlying>> % ;
: emit-base-table ( alist longest -- )
[
return-addresses get empty? [ 0 emit-uint ] [
emit-gc-info-bitmaps
- emit-base-tables
+ emit-base-tables suffix
emit-return-addresses
- 4array emit-uints
+ emit-uints
return-addresses get length emit-uint
] if
] B{ } make ;
{ pic-tag-count cell }
{ pic-tuple-count cell } ;
+! gc-info should be kept in sync with:
+! vm/gc_info.hpp
STRUCT: gc-info
{ scrub-d-count uint read-only }
{ scrub-r-count uint read-only }
+ { check-d-count uint read-only }
+ { check-r-count uint read-only }
{ gc-root-count uint read-only }
{ derived-root-count uint read-only }
{ return-address-count uint read-only } ;
namespace factor {
+// gc_info should be kept in sync with:
+// core/vm/vm.factor
+
struct gc_info {
uint32_t scrub_d_count;
uint32_t scrub_r_count;
+ uint32_t check_d_count;
+ uint32_t check_r_count;
uint32_t gc_root_count;
uint32_t derived_root_count;
uint32_t return_address_count;
cell callsite_bitmap_size() {
- return scrub_d_count + scrub_r_count + gc_root_count;
+ return
+ scrub_d_count +
+ scrub_r_count +
+ check_d_count +
+ check_r_count +
+ gc_root_count;
}
cell total_bitmap_size() {
cell callsite_scrub_d(cell index) { return index * scrub_d_count; }
cell callsite_scrub_r(cell index) {
- return return_address_count * scrub_d_count + index * scrub_r_count;
+ cell base = return_address_count * scrub_d_count;
+ return base + index * scrub_r_count;
}
cell callsite_gc_roots(cell index) {
- return return_address_count * scrub_d_count +
- return_address_count * scrub_r_count + index * gc_root_count;
+ cell base =
+ return_address_count * scrub_d_count +
+ return_address_count * scrub_r_count +
+ return_address_count * check_d_count +
+ return_address_count * check_r_count;
+ return base + index * gc_root_count;
}
uint32_t lookup_base_pointer(cell index, cell derived_root) {