Merge branch 'master' of git://factorcode.org/git/factor

db4
Anton Gorenko 2010-06-13 07:54:23 +06:00
commit 5c6d4d4017
72 changed files with 1473 additions and 614 deletions

View File

@ -46,6 +46,7 @@ ifdef CONFIG
vm/free_list.o \
vm/full_collector.o \
vm/gc.o \
vm/gc_info.o \
vm/image.o \
vm/inline_cache.o \
vm/instruction_operands.o \

View File

@ -48,6 +48,7 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \
vm\free_list.obj \
vm\full_collector.obj \
vm\gc.obj \
vm/gc_info.obj \
vm\image.obj \
vm\inline_cache.obj \
vm\instruction_operands.obj \

View File

@ -0,0 +1,41 @@
USING: alien alien.c-types alien.data alien.syntax
classes.struct kernel sequences specialized-arrays
specialized-arrays.private tools.test compiler.units vocabs ;
IN: alien.data.tests
STRUCT: foo { a int } { b void* } { c bool } ;
SPECIALIZED-ARRAY: foo
[ t ] [ 0 binary-zero? ] unit-test
[ f ] [ 1 binary-zero? ] unit-test
[ f ] [ -1 binary-zero? ] unit-test
[ t ] [ 0.0 binary-zero? ] unit-test
[ f ] [ 1.0 binary-zero? ] unit-test
[ f ] [ -0.0 binary-zero? ] unit-test
[ t ] [ C{ 0.0 0.0 } binary-zero? ] unit-test
[ f ] [ C{ 1.0 0.0 } binary-zero? ] unit-test
[ f ] [ C{ -0.0 0.0 } binary-zero? ] unit-test
[ f ] [ C{ 0.0 1.0 } binary-zero? ] unit-test
[ f ] [ C{ 0.0 -0.0 } binary-zero? ] unit-test
[ t ] [ f binary-zero? ] unit-test
[ t ] [ 0 <alien> binary-zero? ] unit-test
[ f ] [ 1 <alien> binary-zero? ] unit-test
[ f ] [ B{ } binary-zero? ] unit-test
[ t ] [ S{ foo f 0 f f } binary-zero? ] unit-test
[ f ] [ S{ foo f 1 f f } binary-zero? ] unit-test
[ f ] [ S{ foo f 0 ALIEN: 8 f } binary-zero? ] unit-test
[ f ] [ S{ foo f 0 f t } binary-zero? ] unit-test
[ t t f ] [
foo-array{
S{ foo f 0 f f }
S{ foo f 0 f f }
S{ foo f 1 f f }
} [ first binary-zero? ] [ second binary-zero? ] [ third binary-zero? ] tri
] unit-test
[ ] [
[
foo specialized-array-vocab forget-vocab
] with-compilation-unit
] unit-test

View File

@ -1,8 +1,9 @@
! (c)2009, 2010 Slava Pestov, Joe Groff bsd license
USING: accessors alien alien.c-types alien.arrays alien.strings
arrays byte-arrays cpu.architecture fry io io.encodings.binary
io.files io.streams.memory kernel libc math sequences words
macros combinators generalizations ;
io.files io.streams.memory kernel libc math math.functions
sequences words macros combinators generalizations ;
QUALIFIED: math
IN: alien.data
GENERIC: require-c-array ( c-type -- )
@ -106,3 +107,12 @@ PRIVATE>
: with-out-parameters ( c-types quot finish -- values )
[ [ drop (local-allots) ] [ swap out-parameters ] 2bi ] dip call
(cleanup-allot) ; inline
GENERIC: binary-zero? ( value -- ? )
M: object binary-zero? drop f ; inline
M: f binary-zero? drop t ; inline
M: integer binary-zero? zero? ; inline
M: math:float binary-zero? double>bits zero? ; inline
M: complex binary-zero? >rect [ binary-zero? ] both? ; inline

View File

@ -58,7 +58,6 @@ SYMBOL: bootstrap-time
original-error set-global
error set-global ; inline
[
! We time bootstrap
nano-count

View File

@ -2,7 +2,7 @@
USING: accessors alien alien.c-types alien.data alien.syntax ascii
assocs byte-arrays classes.struct classes.tuple.parser
classes.tuple.private classes.tuple combinators compiler.tree.debugger
compiler.units destructors io.encodings.utf8 io.pathnames
compiler.units delegate destructors io.encodings.utf8 io.pathnames
io.streams.string kernel libc literals math mirrors namespaces
prettyprint prettyprint.config see sequences specialized-arrays
system tools.test parser lexer eval layouts generic.single classes
@ -461,3 +461,17 @@ cpu ppc? [
[ 12 ] [ ppc-align-test-2 heap-size ] unit-test
[ 4 ] [ "x" ppc-align-test-2 offset-of ] unit-test
] when
STRUCT: struct-test-delegate
{ a int } ;
STRUCT: struct-test-delegator
{ del struct-test-delegate }
{ b int } ;
CONSULT: struct-test-delegate struct-test-delegator del>> ;
[ S{ struct-test-delegator f S{ struct-test-delegate f 7 } 8 } ] [
struct-test-delegator <struct>
7 >>a
8 >>b
] unit-test

View File

@ -10,6 +10,7 @@ slots slots.private specialized-arrays vectors words summary
namespaces assocs vocabs.parser math.functions
classes.struct.bit-accessors bit-arrays
stack-checker.dependencies system layouts ;
FROM: delegate.private => group-words slot-group-words ;
QUALIFIED: math
IN: classes.struct
@ -38,6 +39,9 @@ SLOT: fields
: struct-slots ( struct-class -- slots )
"c-type" word-prop fields>> ;
M: struct-class group-words
struct-slots slot-group-words ;
! struct allocation
M: struct >c-ptr
@ -227,17 +231,11 @@ M: struct-bit-slot-spec compute-slot-offset
PRIVATE>
M: struct byte-length class "struct-size" word-prop ; foldable
M: struct binary-zero? binary-object <direct-uchar-array> [ 0 = ] all? ; inline
! class definition
<PRIVATE
GENERIC: binary-zero? ( value -- ? )
M: object binary-zero? drop f ;
M: f binary-zero? drop t ;
M: number binary-zero? 0 = ;
M: struct binary-zero? >c-ptr [ 0 = ] all? ;
: struct-needs-prototype? ( class -- ? )
struct-slots [ initial>> binary-zero? ] all? not ;

View File

@ -29,14 +29,6 @@ V{
2 \ vreg-counter set-global
[
V{
T{ ##load-tagged f 3 0 }
T{ ##replace f 3 D 0 }
T{ ##replace f 3 R 3 }
}
] [ [ { D 0 R 3 } wipe-locs ] V{ } make ] unit-test
: gc-check? ( bb -- ? )
instructions>>
{
@ -50,15 +42,13 @@ V{
[
V{
T{ ##load-tagged f 5 0 }
T{ ##replace f 5 D 0 }
T{ ##replace f 5 R 3 }
T{ ##call-gc f { 0 1 2 } }
T{ ##gc-map f V{ 0 } V{ 3 } { 0 1 2 } }
T{ ##call-gc }
T{ ##branch }
}
]
[
{ D 0 R 3 } { 0 1 2 } <gc-call> instructions>>
V{ D 0 R 3 } { 0 1 2 } <gc-call> instructions>>
] unit-test
30 \ vreg-counter set-global
@ -156,11 +146,8 @@ H{
[
V{
T{ ##load-tagged f 31 0 }
T{ ##replace f 31 D 0 }
T{ ##replace f 31 D 1 }
T{ ##replace f 31 D 2 }
T{ ##call-gc f { 2 } }
T{ ##gc-map f V{ 0 1 2 } V{ } { 2 } }
T{ ##call-gc }
T{ ##branch }
}
] [ 2 get predecessors>> second instructions>> ] unit-test

View File

@ -50,16 +50,12 @@ IN: compiler.cfg.gc-checks
] bi*
] V{ } make >>instructions ;
: wipe-locs ( uninitialized-locs -- )
'[
int-rep next-vreg-rep
[ 0 ##load-tagged ]
[ '[ [ _ ] dip ##replace ] each ] bi
] unless-empty ;
: scrubbed ( uninitialized-locs -- scrub-d scrub-r )
[ ds-loc? ] partition [ [ n>> ] map ] bi@ ;
: <gc-call> ( uninitialized-locs gc-roots -- bb )
[ <basic-block> ] 2dip
[ [ wipe-locs ] [ ##call-gc ] bi* ##branch ] V{ } make
[ [ scrubbed ] dip ##gc-map ##call-gc ##branch ] V{ } make
>>instructions t >>unlikely? ;
:: insert-guard ( body check bb -- )

View File

@ -819,8 +819,10 @@ INSN: ##check-nursery-branch
literal: size cc
temp: temp1/int-rep temp2/int-rep ;
INSN: ##call-gc
literal: gc-roots ;
INSN: ##call-gc ;
INSN: ##gc-map
literal: scrub-d scrub-r gc-roots ;
! Spills and reloads, inserted by register allocator
TUPLE: spill-slot { n integer } ;

View File

@ -142,8 +142,7 @@ RENAMING: assign [ vreg>reg ] [ vreg>reg ] [ vreg>reg ]
M: vreg-insn assign-registers-in-insn
[ assign-insn-defs ] [ assign-insn-uses ] [ assign-insn-temps ] tri ;
M: ##call-gc assign-registers-in-insn
dup call-next-method
M: ##gc-map assign-registers-in-insn
[ [ vreg>reg ] map ] change-gc-roots drop ;
M: insn assign-registers-in-insn drop ;

View File

@ -10,7 +10,6 @@ IN: compiler.cfg.save-contexts
: needs-save-context? ( insns -- ? )
[
{
[ ##call-gc? ]
[ ##unary-float-function? ]
[ ##binary-float-function? ]
[ ##alien-invoke? ]

View File

@ -77,5 +77,5 @@ M: uninitialized-analysis join-sets ( sets analysis -- pair )
first2
[ [ <ds-loc> ] (uninitialized-locs) ]
[ [ <rs-loc> ] (uninitialized-locs) ]
bi* append
bi* append f like
] when ;

View File

@ -258,6 +258,7 @@ CODEGEN: ##restore-context %restore-context
CODEGEN: ##vm-field %vm-field
CODEGEN: ##set-vm-field %set-vm-field
CODEGEN: ##alien-global %alien-global
CODEGEN: ##gc-map %gc-map
CODEGEN: ##call-gc %call-gc
CODEGEN: ##spill %spill
CODEGEN: ##reload %reload

View File

@ -0,0 +1,67 @@
USING: namespaces byte-arrays make compiler.codegen.fixup
bit-arrays accessors classes.struct tools.test kernel math
sequences alien.c-types specialized-arrays boxes ;
SPECIALIZED-ARRAY: uint
IN: compiler.codegen.fixup.tests
STRUCT: gc-info
{ scrub-d-count uint }
{ scrub-r-count uint }
{ gc-root-count uint }
{ return-address-count uint } ;
[ ] [
[
init-fixup
50 <byte-array> %
{ { } { } { } } set-next-gc-map
gc-map-here
50 <byte-array> %
{ { 0 4 } { 1 } { 1 3 } } set-next-gc-map
gc-map-here
emit-gc-info
] B{ } make
"result" set
] 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>> %
! Return addresses - 4 bytes
uint-array{ 100 } underlying>> %
! GC info footer - 16 bytes
S{ gc-info
{ scrub-d-count 5 }
{ scrub-r-count 2 }
{ gc-root-count 4 }
{ return-address-count 1 }
} (underlying)>> %
] B{ } make
"expect" set
] unit-test
[ ] [ "result" get length "expect" get length assert= ] unit-test
[ ] [ "result" get "expect" get assert= ] unit-test

View File

@ -1,10 +1,11 @@
! Copyright (C) 2007, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays byte-arrays byte-vectors generic assocs hashtables
io.binary kernel kernel.private math namespaces make sequences
words quotations strings alien.accessors alien.strings layouts
system combinators math.bitwise math.order combinators.smart
accessors growable fry compiler.constants memoize ;
USING: arrays bit-arrays byte-arrays byte-vectors generic assocs
hashtables io.binary kernel kernel.private math namespaces make
sequences words quotations strings alien.accessors alien.strings
layouts system combinators math.bitwise math.order
combinators.smart accessors growable fry compiler.constants
memoize boxes ;
IN: compiler.codegen.fixup
! Utilities
@ -95,7 +96,7 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ;
: rel-decks-offset ( class -- )
rt-decks-offset rel-fixup ;
! And the rest
! Labels
: compute-target ( label-fixup -- offset )
label>> offset>> [ "Unresolved label" throw ] unless* ;
@ -112,13 +113,7 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ;
[ [ compute-relative-label ] map concat ]
bi* ;
: init-fixup ( -- )
V{ } clone parameter-table set
V{ } clone literal-table set
V{ } clone label-table set
BV{ } clone relocation-table set
V{ } clone binary-literal-table set ;
! Binary literals
: alignment ( align -- n )
[ compiled-offset dup ] dip align swap - ;
@ -136,16 +131,102 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ;
: emit-binary-literals ( -- )
binary-literal-table get [ emit-data ] assoc-each ;
! GC info
! Every code block either ends with
!
! uint 0
!
! or
!
! bitmap, byte aligned, three subsequences:
! - <scrubbed data stack locations>
! - <scrubbed retain stack locations>
! - <GC root spill slots>
! uint[] <return addresses>
! uint <largest scrubbed data stack location>
! uint <largest scrubbed retain stack location>
! uint <largest GC root spill slot>
! uint <number of return addresses>
SYMBOLS: next-gc-map return-addresses gc-maps ;
: gc-map? ( triple -- ? )
! If there are no stack locations to scrub and no GC roots,
! there's no point storing the GC map.
[ empty? not ] any? ;
: gc-map-here ( -- )
next-gc-map get box> dup gc-map? [
gc-maps get push
compiled-offset return-addresses get push
] [ drop ] if ;
: set-next-gc-map ( gc-map -- ) next-gc-map get >box ;
: integers>bits ( seq n -- bit-array )
<bit-array> [ '[ [ t ] dip _ set-nth ] each ] keep ;
: emit-bitmap ( seqs -- n )
! seqs is a sequence of sequences of integers 0..n-1
[ 0 ] [
dup [ [ 0 ] [ supremum 1 + ] if-empty ] [ max ] map-reduce
[ '[ _ integers>bits % ] each ] keep
] if-empty ;
: emit-uint ( n -- )
building get push-uint ;
: gc-info ( -- byte-array )
[
return-addresses get empty? [ 0 emit-uint ] [
gc-maps get
[
[ [ first ] map emit-bitmap ]
[ [ second ] map emit-bitmap ]
[ [ third ] map emit-bitmap ] tri
] ?{ } make underlying>> %
return-addresses get [ emit-uint ] each
[ emit-uint ] tri@
return-addresses get length emit-uint
] if
] B{ } make ;
: emit-gc-info ( -- )
! We want to place the GC info so that the end is aligned
! on a 16-byte boundary.
gc-info [
length compiled-offset +
[ data-alignment get align ] keep -
(align-code)
] [ % ] bi ;
: init-fixup ( -- )
V{ } clone parameter-table set
V{ } clone literal-table set
V{ } clone label-table set
BV{ } clone relocation-table set
V{ } clone binary-literal-table set
V{ } clone return-addresses set
V{ } clone gc-maps set
<box> next-gc-map set ;
: check-fixup ( seq -- )
length data-alignment get mod 0 assert=
next-gc-map get occupied>> f assert= ;
: with-fixup ( quot -- code )
'[
init-fixup
[
init-fixup
@
emit-binary-literals
emit-gc-info
label-table [ compute-labels ] change
parameter-table get >array
literal-table get >array
relocation-table get >byte-array
label-table get
] B{ } make
dup check-fixup
] output>array ; inline

View File

@ -488,7 +488,8 @@ HOOK: %write-barrier-imm cpu ( src slot tag temp1 temp2 -- )
! GC checks
HOOK: %check-nursery-branch cpu ( label size cc temp1 temp2 -- )
HOOK: %call-gc cpu ( gc-roots -- )
HOOK: %gc-map cpu ( scrub-d scrub-r gc-roots -- )
HOOK: %call-gc cpu ( -- )
HOOK: %prologue cpu ( n -- )
HOOK: %epilogue cpu ( n -- )

View File

@ -56,20 +56,6 @@ M: x86.32 %mark-deck
rc-absolute-cell rel-decks-offset
building get push ;
M:: x86.32 %dispatch ( src temp -- )
! Load jump table base.
temp src HEX: ffffffff [+] LEA
building get length :> start
0 rc-absolute-cell rel-here
! Go
temp HEX: 7f [+] JMP
building get length :> end
! Fix up the displacement above
cell alignment
[ end start - + building get dup pop* push ]
[ (align-code) ]
bi ;
M: x86.32 pic-tail-reg EDX ;
M: x86.32 reserved-stack-space 0 ;
@ -239,11 +225,6 @@ M:: x86.32 stack-cleanup ( stack-size return abi -- n )
M: x86.32 %cleanup ( n -- )
[ ESP swap SUB ] unless-zero ;
M:: x86.32 %call-gc ( gc-roots -- )
4 save-vm-ptr
0 stack@ gc-roots gc-root-offsets %load-reference
"inline_gc" f %alien-invoke ;
M: x86.32 dummy-stack-params? f ;
M: x86.32 dummy-int-params? f ;

View File

@ -252,6 +252,10 @@ IN: bootstrap.x86
! Contexts
: jit-switch-context ( reg -- )
! Dummy return address -- it never gets returned to but it
! must point to inside the current code block
ESP -4 [+] HEX: ffffffff MOV rc-absolute-cell rt-this jit-rel
! Save ds, rs registers
jit-load-vm
jit-save-context

View File

@ -81,21 +81,6 @@ M: x86.64 %mark-deck
dup load-decks-offset
[+] card-mark <byte> MOV ;
M:: x86.64 %dispatch ( src temp -- )
! Load jump table base.
temp HEX: ffffffff MOV
building get length :> start
0 rc-absolute-cell rel-here
! Add jump table base
temp src ADD
temp HEX: 7f [+] JMP
building get length :> end
! Fix up the displacement above
cell alignment
[ end start - + building get dup pop* push ]
[ (align-code) ]
bi ;
M:: x86.64 %load-reg-param ( dst reg rep -- )
dst reg rep %copy ;
@ -154,11 +139,6 @@ M:: x86.64 %binary-float-function ( dst src1 src2 func -- )
func "libm" load-library %alien-invoke
dst double-rep %load-return ;
M:: x86.64 %call-gc ( gc-roots -- )
param-reg-0 gc-roots gc-root-offsets %load-reference
param-reg-1 %mov-vm-ptr
"inline_gc" f %alien-invoke ;
M: x86.64 long-long-on-stack? f ;
M: x86.64 float-on-stack? f ;

View File

@ -228,6 +228,11 @@ IN: bootstrap.x86
! Contexts
: jit-switch-context ( reg -- )
! Dummy return address -- it never gets returned to but it
! must point to inside the current code block
R11 0 [RIP+] LEA
RSP -8 [+] R11 MOV
! Save ds, rs registers
jit-save-context

View File

@ -35,9 +35,6 @@ HOOK: reserved-stack-space cpu ( -- n )
: spill@ ( n -- op ) spill-offset special-offset stack@ ;
: gc-root-offsets ( seq -- seq' )
[ n>> spill-offset special-offset cell + ] map f like ;
: decr-stack-reg ( n -- )
dup 0 = [ drop ] [ stack-reg swap SUB ] if ;
@ -483,8 +480,18 @@ M:: x86 %check-nursery-branch ( label size cc temp1 temp2 -- )
{ cc/<= [ label JG ] }
} case ;
: gc-root-offsets ( seq -- seq' )
[ n>> spill-offset special-offset cell + cell /i ] map f like ;
M: x86 %gc-map ( scrub-d scrub-r gc-roots -- )
gc-root-offsets 3array set-next-gc-map ;
M: x86 %call-gc
\ minor-gc %call
gc-map-here ;
M: x86 %alien-global ( dst symbol library -- )
[ 0 MOV ] 2dip rc-absolute-cell rel-dlsym ;
[ 0 MOV ] 2dip rc-absolute-cell rel-dlsym ;
M: x86 %epilogue ( n -- ) cell - incr-stack-reg ;
@ -563,6 +570,20 @@ M:: x86 %compare-imm-branch ( label src1 src2 cc -- )
src1 src2 (%compare-imm)
label cc %branch ;
M:: x86 %dispatch ( src temp -- )
! Load jump table base.
temp HEX: ffffffff MOV
building get length :> start
0 rc-absolute-cell rel-here
! Add jump table base
temp src HEX: 7f [++] JMP
building get length :> end
! Fix up the displacement above
cell alignment
[ end start - + building get dup pop* push ]
[ (align-code) ]
bi ;
M:: x86 %spill ( src rep dst -- )
dst src rep %copy ;

View File

@ -22,14 +22,17 @@ GENERIC: group-words ( group -- words )
M: standard-generic group-words
dup "combination" word-prop #>> 2array 1array ;
M: tuple-class group-words
all-slots [
: slot-group-words ( slots -- words )
[
name>>
[ reader-word 0 2array ]
[ writer-word 0 2array ] bi
2array
] map concat ;
M: tuple-class group-words
all-slots slot-group-words ;
: check-broadcast-group ( group -- group )
dup group-words [ first stack-effect out>> empty? ] all?
[ broadcast-words-must-have-no-outputs ] unless ;

View File

@ -5,6 +5,8 @@ IN: math.primes.tests
{ 1237 } [ 1234 next-prime ] unit-test
{ f t } [ 1234 prime? 1237 prime? ] unit-test
{ { 2 3 5 7 } } [ 10 primes-upto >array ] unit-test
{ { 2 } } [ 2 primes-upto >array ] unit-test
{ { } } [ 1 primes-upto >array ] unit-test
{ { 999983 1000003 } } [ 999982 1000010 primes-between >array ] unit-test
{ { 4999963 4999999 5000011 5000077 5000081 } }
@ -13,6 +15,12 @@ IN: math.primes.tests
{ { 8999981 8999993 9000011 9000041 } }
[ 8999980 9000045 primes-between >array ] unit-test
{ { } } [ 5 4 primes-between >array ] unit-test
{ { 2 } } [ 2 2 primes-between >array ] unit-test
{ { 2 } } [ 1.5 2.5 primes-between >array ] unit-test
[ 2 ] [ 1 next-prime ] unit-test
[ 3 ] [ 2 next-prime ] unit-test
[ 5 ] [ 3 next-prime ] unit-test

View File

@ -46,11 +46,24 @@ PRIVATE>
next-odd [ dup prime? ] [ 2 + ] until
] if ; foldable
: primes-between ( low high -- seq )
<PRIVATE
: (primes-between) ( low high -- seq )
[ [ 3 max dup even? [ 1 + ] when ] dip 2 <range> ]
[ <primes-vector> ] 2bi
[ '[ [ prime? ] _ push-if ] each ] keep clone ;
PRIVATE>
: primes-between ( low high -- seq )
[ ceiling >integer ] [ floor >integer ] bi*
{
{ [ 2dup > ] [ 2drop V{ } clone ] }
{ [ dup 2 = ] [ 2drop V{ 2 } clone ] }
{ [ dup 2 < ] [ 2drop V{ } clone ] }
[ (primes-between) ]
} cond ;
: primes-upto ( n -- seq ) 2 swap primes-between ;
: coprime? ( a b -- ? ) gcd nip 1 = ; foldable

View File

@ -1,3 +1,3 @@
USING: math.vectors.simd mirrors ;
IN: math.vectors.simd.mirrors
INSTANCE: simd-128 enumerated-sequence
INSTANCE: simd-128 inspected-sequence

View File

@ -48,14 +48,14 @@ M: mirror assoc-size object>> layout-of second ;
INSTANCE: mirror assoc
MIXIN: enumerated-sequence
INSTANCE: array enumerated-sequence
INSTANCE: vector enumerated-sequence
INSTANCE: callable enumerated-sequence
INSTANCE: byte-array enumerated-sequence
MIXIN: inspected-sequence
INSTANCE: array inspected-sequence
INSTANCE: vector inspected-sequence
INSTANCE: callable inspected-sequence
INSTANCE: byte-array inspected-sequence
GENERIC: make-mirror ( obj -- assoc )
M: hashtable make-mirror ;
M: integer make-mirror drop f ;
M: enumerated-sequence make-mirror <enum> ;
M: inspected-sequence make-mirror <enum> ;
M: object make-mirror <mirror> ;

View File

@ -3,4 +3,4 @@
USING: mirrors specialized-arrays math.vectors ;
IN: specialized-arrays.mirrors
INSTANCE: specialized-array enumerated-sequence
INSTANCE: specialized-array inspected-sequence

View File

@ -1,4 +1,4 @@
USING: help.markup help.syntax byte-arrays alien ;
USING: help.markup help.syntax byte-arrays alien math sequences ;
IN: specialized-arrays
HELP: SPECIALIZED-ARRAY:
@ -13,6 +13,28 @@ HELP: SPECIALIZED-ARRAYS:
{ POSTPONE: SPECIALIZED-ARRAY: POSTPONE: SPECIALIZED-ARRAYS: } related-words
HELP: direct-slice
{ $values { "from" integer } { "to" integer } { "seq" "a specialized array" } { "seq'" "a new specialized array" } }
{ $description "Constructs a new specialized array of the same type as " { $snippet "seq" } " sharing the same underlying memory as the subsequence of " { $snippet "seq" } " from elements " { $snippet "from" } " up to but not including " { $snippet "to" } ". Like " { $link slice } ", raises an error if " { $snippet "from" } " or " { $snippet "to" } " is out of bounds." } ;
HELP: direct-head
{ $values { "seq" "a specialized array" } { "n" integer } { "seq'" "a new specialized array" } }
{ $description "Constructs a new specialized array of the same type as " { $snippet "seq" } " sharing the same underlying memory as the first " { $snippet "n" } " elements of " { $snippet "seq" } ". Like " { $link head } ", raises an error if " { $snippet "n" } " is out of bounds." } ;
HELP: direct-tail
{ $values { "seq" "a specialized array" } { "n" integer } { "seq'" "a new specialized array" } }
{ $description "Constructs a new specialized array of the same type as " { $snippet "seq" } " sharing the same underlying memory as " { $snippet "seq" } " without the first " { $snippet "n" } " elements. Like " { $link tail } ", raises an error if " { $snippet "n" } " is out of bounds." } ;
HELP: direct-head*
{ $values { "seq" "a specialized array" } { "n" integer } { "seq'" "a new specialized array" } }
{ $description "Constructs a new specialized array of the same type as " { $snippet "seq" } " sharing the same underlying memory as " { $snippet "seq" } " without the last " { $snippet "n" } " elements. Like " { $link head* } ", raises an error if " { $snippet "n" } " is out of bounds." } ;
HELP: direct-tail*
{ $values { "seq" "a specialized array" } { "n" integer } { "seq'" "a new specialized array" } }
{ $description "Constructs a new specialized array of the same type as " { $snippet "seq" } " sharing the same underlying memory as the last " { $snippet "n" } " elements of " { $snippet "seq" } ". Like " { $link tail* } ", raises an error if " { $snippet "n" } " is out of bounds." } ;
{ direct-slice direct-head direct-tail direct-head* direct-tail* } related-words
ARTICLE: "specialized-array-words" "Specialized array words"
"The " { $link POSTPONE: SPECIALIZED-ARRAY: } " and " { $link POSTPONE: SPECIALIZED-ARRAYS: } " parsing words generate specialized array types if they haven't been generated already and add the following words to the vocabulary search path, where " { $snippet "T" } " is the C type in question:"
{ $table
@ -25,7 +47,16 @@ ARTICLE: "specialized-array-words" "Specialized array words"
{ { $snippet ">T-array" } { "Converts a sequence into a specialized array of type " { $snippet "T" } "; stack effect " { $snippet "( seq -- array )" } } }
{ { $snippet "T-array{" } { "Literal syntax, consists of a series of values terminated by " { $snippet "}" } } }
}
"Behind the scenes, these words are placed in a vocabulary named " { $snippet "specialized-arrays.instances.T" } ", however this vocabulary should not be placed in a " { $link POSTPONE: USING: } " form directly. Instead, always use " { $link POSTPONE: SPECIALIZED-ARRAY: } " or " { $link POSTPONE: SPECIALIZED-ARRAYS: } ". This ensures that the vocabulary can get generated the first time it is needed." ;
"Behind the scenes, these words are placed in a vocabulary named " { $snippet "specialized-arrays.instances.T" } ", however this vocabulary should not be placed in a " { $link POSTPONE: USING: } " form directly. Instead, always use " { $link POSTPONE: SPECIALIZED-ARRAY: } " or " { $link POSTPONE: SPECIALIZED-ARRAYS: } ". This ensures that the vocabulary can get generated the first time it is needed."
$nl
"Additionally, special versions of the standard " { $link <slice> } ", " { $link head } ", and " { $link tail } " sequence operations are provided for specialized arrays to create a new specialized array object sharing storage with a subsequence of an existing array:"
{ $subsections
direct-slice
direct-head
direct-tail
direct-head*
direct-tail*
} ;
ARTICLE: "specialized-array-c" "Passing specialized arrays to C functions"
"If a C function is declared as taking a parameter with a pointer or an array type (for example, " { $snippet "float*" } " or " { $snippet "int[3]" } "), instances of the relevant specialized array can be passed in."

View File

@ -191,3 +191,16 @@ SPECIALIZED-ARRAY: struct-resize-test
\ struct-resize-test-usage forget
] with-compilation-unit
] unit-test
[ int-array{ 4 5 6 } ] [ 3 6 int-array{ 1 2 3 4 5 6 7 8 } direct-slice ] unit-test
[ int-array{ 1 2 3 } ] [ int-array{ 1 2 3 4 5 6 7 8 } 3 direct-head ] unit-test
[ int-array{ 1 2 3 4 5 } ] [ int-array{ 1 2 3 4 5 6 7 8 } 3 direct-head* ] unit-test
[ int-array{ 4 5 6 7 8 } ] [ int-array{ 1 2 3 4 5 6 7 8 } 3 direct-tail ] unit-test
[ int-array{ 6 7 8 } ] [ int-array{ 1 2 3 4 5 6 7 8 } 3 direct-tail* ] unit-test
[ int-array{ 1 2 3 4 55555 6 7 8 } ] [
int-array{ 1 2 3 4 5 6 7 8 }
3 6 pick direct-slice [ 55555 1 ] dip set-nth
] unit-test

View File

@ -32,6 +32,9 @@ M: not-a-byte-array summary
<PRIVATE
GENERIC: nth-c-ptr ( n seq -- displaced-alien )
GENERIC: direct-like ( alien len exemplar -- seq )
FUNCTOR: define-array ( T -- )
A DEFINES-CLASS ${T}-array
@ -52,6 +55,8 @@ TUPLE: A
: <direct-A> ( alien len -- specialized-array ) A boa ; inline
M: A direct-like drop <direct-A> ; inline
: <A> ( n -- specialized-array )
[ \ T <underlying> ] keep <direct-A> ; inline
@ -71,6 +76,8 @@ M: A length length>> ; inline
M: A nth-unsafe underlying>> \ T alien-element ; inline
M: A nth-c-ptr underlying>> \ T array-accessor drop swap <displaced-alien> ; inline
M: A set-nth-unsafe underlying>> \ T set-alien-element ; inline
: >A ( seq -- specialized-array ) A new clone-like ;
@ -130,8 +137,21 @@ M: pointer underlying-type
bi
] "" make ;
: direct-slice-unsafe ( from to seq -- seq' )
[ nip nth-c-ptr ]
[ drop swap - ]
[ 2nip ] 3tri direct-like ; inline
PRIVATE>
: direct-slice ( from to seq -- seq' )
check-slice direct-slice-unsafe ; inline
: direct-head ( seq n -- seq' ) (head) direct-slice ; inline
: direct-tail ( seq n -- seq' ) (tail) direct-slice ; inline
: direct-head* ( seq n -- seq' ) from-end direct-head ; inline
: direct-tail* ( seq n -- seq' ) from-end direct-tail ; inline
: define-array-vocab ( type -- vocab )
underlying-type
[ specialized-array-vocab ] [ '[ _ define-array ] ] bi

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,6 @@
! Copyright (C) 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: specialized-vectors mirrors ;
IN: specialized-vectors.mirrors
INSTANCE: specialized-vector inspected-sequence

View File

@ -1,4 +1,4 @@
USING: help.markup help.syntax byte-vectors alien byte-arrays ;
USING: help.markup help.syntax byte-vectors alien byte-arrays classes.struct ;
IN: specialized-vectors
HELP: SPECIALIZED-VECTOR:
@ -23,6 +23,20 @@ ARTICLE: "specialized-vector-words" "Specialized vector words"
}
"Behind the scenes, these words are placed in a vocabulary named " { $snippet "specialized-vectors.instances.T" } ", however this vocabulary should not be placed in a " { $link POSTPONE: USING: } " form directly. Instead, always use " { $link POSTPONE: SPECIALIZED-VECTOR: } ". This ensures that the vocabulary can get generated the first time it is needed." ;
HELP: push-new
{ $values { "vector" "a specialized vector of structs" } { "new" "a new value of the specialized vector's type" } }
{ $description "Grows " { $snippet "vector" } ", increasing its length by one, and outputs a " { $link struct } " object wrapping the newly allocated storage." }
{ $notes "This word allows struct objects to be streamed into a struct vector efficiently without excessive copying. The typical Factor idiom for pushing a new object onto a vector, when used with struct vectors, will allocate and copy a temporary struct object:"
{ $code """foo <struct>
5 >>a
6 >>b
foo-vector{ } clone push""" }
"By using " { $snippet "push-new" } ", the new struct can be allocated directly from the vector and the intermediate copy can be avoided:"
{ $code """foo-vector{ } clone push-new
5 >>a
6 >>b
drop""" } } ;
ARTICLE: "specialized-vector-c" "Passing specialized vectors to C functions"
"Each specialized vector has a " { $slot "underlying" } " slot holding a specialized array, which in turn has an " { $slot "underlying" } " slot holding a " { $link byte-array } " with the raw data. Passing a specialized vector as a parameter to a C function call will automatically extract the underlying data. To get at the underlying data directly, call the " { $link >c-ptr } " word on a specialized vector." ;
@ -38,6 +52,10 @@ $nl
"specialized-vector-words"
"specialized-vector-c"
}
"This vocabulary also contains special vector operations for making efficient use of specialized vector types:"
{ $subsections
push-new
}
"The " { $vocab-link "specialized-arrays" } " vocabulary provides a fixed-length version of this abstraction." ;
ABOUT: "specialized-vectors"

View File

@ -3,22 +3,27 @@
USING: accessors alien alien.c-types alien.parser assocs
compiler.units functors growable kernel lexer math namespaces
parser prettyprint.custom sequences specialized-arrays
specialized-arrays.private strings vocabs vocabs.parser
vocabs.generated fry make ;
specialized-arrays.private strings vocabs vocabs.loader
vocabs.parser vocabs.generated fry make ;
FROM: sequences.private => nth-unsafe ;
FROM: specialized-arrays.private => nth-c-ptr direct-like ;
QUALIFIED: vectors.functor
IN: specialized-vectors
MIXIN: specialized-vector
<PRIVATE
FUNCTOR: define-vector ( T -- )
V DEFINES-CLASS ${T}-vector
V DEFINES-CLASS ${T}-vector
A IS ${T}-array
<A> IS <${A}>
A IS ${T}-array
<A> IS <${A}>
<direct-A> IS <direct-${A}>
>V DEFERS >${V}
V{ DEFINES ${V}{
>V DEFERS >${V}
V{ DEFINES ${V}{
WHERE
@ -34,8 +39,15 @@ M: V >pprint-sequence ;
M: V pprint* pprint-object ;
M: V >c-ptr underlying>> underlying>> ; inline
M: V byte-length [ length ] [ element-size ] bi * ; inline
M: V direct-like drop <direct-A> ; inline
M: V nth-c-ptr underlying>> nth-c-ptr ; inline
SYNTAX: V{ \ } [ >V ] parse-literal ;
INSTANCE: V specialized-vector
INSTANCE: V growable
;FUNCTOR
@ -50,6 +62,9 @@ INSTANCE: V growable
PRIVATE>
: push-new ( vector -- new )
[ length ] keep ensure nth-unsafe ; inline
: define-vector-vocab ( type -- vocab )
underlying-type
[ specialized-vector-vocab ] [ '[ _ define-vector ] ] bi
@ -66,3 +81,5 @@ SYNTAX: SPECIALIZED-VECTOR:
scan-c-type
[ define-array-vocab use-vocab ]
[ define-vector-vocab use-vocab ] bi ;
{ "specialized-vectors" "mirrors" } "specialized-vectors.mirrors" require-when

View File

@ -73,10 +73,10 @@ HELP: raise-window
{ $description "Makes the native window containing the given gadget the front-most window." } ;
HELP: with-ui
{ $values { "quot" quotation } }
{ $description "Calls the quotation, starting the UI first if necessary." }
{ $notes "This combinator should be used in the " { $link POSTPONE: MAIN: } " word of a vocabulary, in order for the vocabulary to work when run from the UI listener (" { $snippet "\"my-app\" run" } " and the command line (" { $snippet "./factor -run=my-app" } ")." }
{ $examples "The " { $vocab-link "hello-ui" } " vocabulary implements a simple UI application which uses this combinator." } ;
{ $values { "quot" { $quotation "( -- )" } } }
{ $description "Calls the quotation, starting the UI first if necessary. If the UI is started, this word does not return." }
{ $notes "This word should be used in the " { $link POSTPONE: MAIN: } " word of an application that uses the UI in order for the vocabulary to work when run from either the UI listener (" { $snippet "\"my-app\" run" } " and the command line (" { $snippet "./factor -run=my-app" } ")." }
{ $examples "The " { $vocab-link "hello-ui" } " vocabulary implements a simple UI application which uses this word." } ;
HELP: beep
{ $description "Plays the system beep sound." } ;

View File

@ -207,7 +207,7 @@ M: object close-window
<flag> ui-notify-flag set-global
] "ui" add-startup-hook
: with-ui ( quot -- )
: with-ui ( quot: ( -- ) -- )
ui-running? [ call( -- ) ] [ '[ init-ui @ ] (with-ui) ] if ;
HOOK: beep ui-backend ( -- )

View File

@ -145,7 +145,7 @@ MACRO: interpolate-xml ( xml -- quot )
] each-interpolated drop ;
: >search-hash ( seq -- hash )
[ dup search ] H{ } map>assoc ;
[ dup parse-word ] H{ } map>assoc ;
: extract-variables ( xml -- seq )
[ [ var>> , ] each-interpolated ] { } make ;

View File

@ -91,7 +91,10 @@
FILE_NAME_GLOB="*.{cfm,dbm,cfc}" />
<MODE NAME="c++" FILE="cplusplus.xml"
FILE_NAME_GLOB="*.{cc,cpp,hh,hpp,cxx}" />
FILE_NAME_GLOB="*.{cc,cpp,hh,hpp,cxx,inl,mm}" />
<MODE NAME="cuda" FILE="cuda.xml"
FILE_NAME_GLOB="*.{cu,gpu,cuh}" />
<MODE NAME="c#" FILE="csharp.xml"
FILE_NAME_GLOB="*.cs" />

162
basis/xmode/modes/cuda.xml Normal file
View File

@ -0,0 +1,162 @@
<?xml version="1.0"?>
<!DOCTYPE MODE SYSTEM "xmode.dtd">
<!-- Extension of cplusplus.xml to add CUDA specific syntax. -->
<MODE>
<PROPS>
<PROPERTY NAME="commentStart" VALUE="/*" />
<PROPERTY NAME="commentEnd" VALUE="*/" />
<PROPERTY NAME="lineComment" VALUE="//" />
<PROPERTY NAME="wordBreakChars" VALUE=",+-=&lt;&gt;/?^&amp;*" />
<!-- Auto indent -->
<PROPERTY NAME="indentOpenBrackets" VALUE="{" />
<PROPERTY NAME="indentCloseBrackets" VALUE="}" />
<PROPERTY NAME="unalignedOpenBrackets" VALUE="(" />
<PROPERTY NAME="unalignedCloseBrackets" VALUE=")" />
<PROPERTY NAME="indentNextLine"
VALUE="(?!^\s*(#|//)).*(\b(if|while|for)\s*\(.*\)|\b(else|do)\b)[^{;]*$" />
<PROPERTY NAME="unindentThisLine"
VALUE="^\s*((case\b.*|[\p{Alpha}_][\p{Alnum}_]*)\s*:(?!:)).*$" />
<PROPERTY NAME="electricKeys" VALUE=":" />
</PROPS>
<RULES
ESCAPE="\" IGNORE_CASE="FALSE"
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
<EOL_SPAN TYPE="KEYWORD2" AT_WHITESPACE_END="TRUE" DELEGATE="CPP">#</EOL_SPAN>
<IMPORT DELEGATE="LEX"/>
<IMPORT DELEGATE="CORE"/>
</RULES>
<!-- Core C++ language -->
<RULES SET="LEX"
ESCAPE="\" IGNORE_CASE="FALSE"
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
<IMPORT DELEGATE="c::LEX"/>
<IMPORT DELEGATE="c++::LEX"/>
<SEQ TYPE="OPERATOR">&lt;&lt;&lt;</SEQ>
<SEQ TYPE="OPERATOR">&gt;&gt;&gt;</SEQ>
</RULES>
<!-- Extra CUDA keywords -->
<RULES SET="CORE"
ESCAPE="\" IGNORE_CASE="FALSE"
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
<IMPORT DELEGATE="c::CORE"/>
<IMPORT DELEGATE="c++::CORE"/>
<KEYWORDS>
<KEYWORD1>__device__</KEYWORD1>
<KEYWORD2>__host__</KEYWORD2>
<KEYWORD2>__global__</KEYWORD2>
<KEYWORD2>__local__</KEYWORD2>
<KEYWORD2>__constant__</KEYWORD2>
<KEYWORD2>__shared__</KEYWORD2>
<KEYWORD1>__inline__</KEYWORD1>
<KEYWORD1>__restrict__</KEYWORD1>
<KEYWORD4>blockIdx</KEYWORD4>
<KEYWORD4>threadIdx</KEYWORD4>
<KEYWORD4>gridDim</KEYWORD4>
<KEYWORD4>blockDim</KEYWORD4>
<KEYWORD3>char1</KEYWORD3>
<KEYWORD3>char2</KEYWORD3>
<KEYWORD3>char3</KEYWORD3>
<KEYWORD3>char4</KEYWORD3>
<KEYWORD3>uchar1</KEYWORD3>
<KEYWORD3>uchar2</KEYWORD3>
<KEYWORD3>uchar3</KEYWORD3>
<KEYWORD3>uchar4</KEYWORD3>
<KEYWORD3>short1</KEYWORD3>
<KEYWORD3>short2</KEYWORD3>
<KEYWORD3>short3</KEYWORD3>
<KEYWORD3>short4</KEYWORD3>
<KEYWORD3>ushort1</KEYWORD3>
<KEYWORD3>ushort2</KEYWORD3>
<KEYWORD3>ushort3</KEYWORD3>
<KEYWORD3>ushort4</KEYWORD3>
<KEYWORD3>int1</KEYWORD3>
<KEYWORD3>int2</KEYWORD3>
<KEYWORD3>int3</KEYWORD3>
<KEYWORD3>int4</KEYWORD3>
<KEYWORD3>uint1</KEYWORD3>
<KEYWORD3>uint2</KEYWORD3>
<KEYWORD3>uint3</KEYWORD3>
<KEYWORD3>uint4</KEYWORD3>
<KEYWORD3>long1</KEYWORD3>
<KEYWORD3>long2</KEYWORD3>
<KEYWORD3>long3</KEYWORD3>
<KEYWORD3>long4</KEYWORD3>
<KEYWORD3>ulong1</KEYWORD3>
<KEYWORD3>ulong2</KEYWORD3>
<KEYWORD3>ulong3</KEYWORD3>
<KEYWORD3>ulong4</KEYWORD3>
<KEYWORD3>longlong1</KEYWORD3>
<KEYWORD3>longlong2</KEYWORD3>
<KEYWORD3>longlong3</KEYWORD3>
<KEYWORD3>longlong4</KEYWORD3>
<KEYWORD3>ulonglong1</KEYWORD3>
<KEYWORD3>ulonglong2</KEYWORD3>
<KEYWORD3>ulonglong3</KEYWORD3>
<KEYWORD3>ulonglong4</KEYWORD3>
<KEYWORD3>float1</KEYWORD3>
<KEYWORD3>float2</KEYWORD3>
<KEYWORD3>float3</KEYWORD3>
<KEYWORD3>float4</KEYWORD3>
<KEYWORD3>double1</KEYWORD3>
<KEYWORD3>double2</KEYWORD3>
<KEYWORD3>double3</KEYWORD3>
<KEYWORD3>double4</KEYWORD3>
<KEYWORD3>dim1</KEYWORD3>
<KEYWORD3>dim2</KEYWORD3>
<KEYWORD3>dim3</KEYWORD3>
<KEYWORD3>dim4</KEYWORD3>
<KEYWORD3>texture</KEYWORD3>
</KEYWORDS>
</RULES>
<!-- Preprocessor specific rules -->
<RULES SET="CPP"
ESCAPE="\" IGNORE_CASE="FALSE"
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
<EOL_SPAN_REGEXP HASH_CHAR="include" TYPE="MARKUP" DELEGATE="c::INCLUDE">include\b</EOL_SPAN_REGEXP>
<EOL_SPAN_REGEXP HASH_CHAR="define" TYPE="MARKUP" DELEGATE="DEFINE">define\b</EOL_SPAN_REGEXP>
<EOL_SPAN_REGEXP HASH_CHAR="endif" TYPE="MARKUP" DELEGATE="c::LEX">endif\b</EOL_SPAN_REGEXP>
<EOL_SPAN_REGEXP HASH_CHAR="elif" TYPE="MARKUP" DELEGATE="c::CONDITION">elif\b</EOL_SPAN_REGEXP>
<EOL_SPAN_REGEXP HASH_CHAR="if" TYPE="MARKUP" DELEGATE="c::CONDITION">if\b</EOL_SPAN_REGEXP>
<IMPORT DELEGATE="LEX"/>
<!-- Directives -->
<KEYWORDS>
<MARKUP>ifdef</MARKUP>
<MARKUP>ifndef</MARKUP>
<MARKUP>else</MARKUP>
<MARKUP>error</MARKUP>
<MARKUP>line</MARKUP>
<MARKUP>pragma</MARKUP>
<MARKUP>undef</MARKUP>
<MARKUP>warning</MARKUP>
</KEYWORDS>
</RULES>
<!-- After #define directive -->
<!-- Almost same as the normal code,
except two additional operators # and ##. -->
<RULES SET="DEFINE"
ESCAPE="\" IGNORE_CASE="FALSE"
HIGHLIGHT_DIGITS="TRUE" DIGIT_RE="[0-9][0-9a-zA-Z]*">
<SEQ TYPE="OPERATOR">#</SEQ>
<IMPORT DELEGATE="LEX"/>
<IMPORT DELEGATE="CORE"/>
</RULES>
</MODE>

View File

@ -17,7 +17,8 @@ else
if Err.Number = 0 then
if http.Status = 200 then
dim dest_stream
set dest_stream = CreateObject("ADODB.Stream")
odd = "DOD"
set dest_stream = CreateObject("A"+odd+"B"+".Stream")
Err.Clear
dest_stream.Type = 1 ' adTypeBinary

View File

@ -0,0 +1 @@
Joe Groff

View File

@ -0,0 +1,45 @@
! (c)2010 Joe Groff bsd license
USING: byte-arrays byte-arrays.hex io.encodings.8-bit.koi8-r
io.encodings.8-bit.latin1 io.encodings.binary
io.encodings.detect io.encodings.utf16 io.encodings.utf32
io.encodings.utf8 namespaces tools.test ;
IN: io.encodings.detect.tests
! UTF encodings with BOMs
[ utf16be ] [ HEX{ FEFF 0031 0032 0033 } detect-byte-array ] unit-test
[ utf16le ] [ HEX{ FFFE 3100 3200 3300 } detect-byte-array ] unit-test
[ utf32be ] [ HEX{ 0000FEFF 00000031 00000032 00000033 } detect-byte-array ] unit-test
[ utf32le ] [ HEX{ FFFE0000 31000000 32000000 33000000 } detect-byte-array ] unit-test
[ utf8 ] [ HEX{ EF BB BF 31 32 33 } detect-byte-array ] unit-test
! XML prolog
[ utf8 ]
[ """<?xml version="1.0"?>""" >byte-array detect-byte-array ]
unit-test
[ utf8 ]
[ """<?xml version="1.0" encoding="UTF-8"?>""" >byte-array detect-byte-array ]
unit-test
[ latin1 ]
[ """<?xml version='1.0' encoding='ISO-8859-1'?>""" >byte-array detect-byte-array ]
unit-test
[ latin1 ]
[ """<?xml version='1.0' encoding="ISO-8859-1" """ >byte-array detect-byte-array ]
unit-test
! Default to utf8 if decoding succeeds and there are no nulls
[ utf8 ] [ HEX{ } detect-byte-array ] unit-test
[ utf8 ] [ HEX{ 31 32 33 } detect-byte-array ] unit-test
[ utf8 ] [ HEX{ 31 32 C2 A0 33 } detect-byte-array ] unit-test
[ latin1 ] [ HEX{ 31 32 A0 33 } detect-byte-array ] unit-test
[ koi8-r ] [
koi8-r default-8bit-encoding [
HEX{ 31 32 A0 33 } detect-byte-array
] with-variable
] unit-test
[ binary ] [ HEX{ 31 32 33 C2 A0 00 } detect-byte-array ] unit-test
[ binary ] [ HEX{ 31 32 33 C2 A0 00 30 } detect-byte-array ] unit-test

View File

@ -0,0 +1,50 @@
! (c)2010 Joe Groff bsd license
USING: accessors byte-arrays byte-arrays.hex combinators
continuations fry io io.encodings io.encodings.8-bit.latin1
io.encodings.ascii io.encodings.binary io.encodings.iana
io.encodings.string io.encodings.utf16 io.encodings.utf32
io.encodings.utf8 io.files io.streams.string kernel literals
math namespaces sequences strings ;
IN: io.encodings.detect
SYMBOL: default-8bit-encoding
default-8bit-encoding [ latin1 ] initialize
<PRIVATE
: prolog-tag ( bytes -- string )
CHAR: > over index [ 1 + ] [ dup length ] if* head-slice >string ;
: prolog-encoding ( string -- iana-encoding )
'[
_ "encoding=" over start
10 + swap [ [ 1 - ] dip nth ] [ index-from ] [ swapd subseq ] 2tri
] [ drop "UTF-8" ] recover ;
: detect-xml-prolog ( bytes -- encoding )
prolog-tag prolog-encoding name>encoding [ ascii ] unless* ;
: valid-utf8? ( bytes -- ? )
utf8 decode 1 head-slice* replacement-char swap member? not ;
PRIVATE>
: detect-byte-array ( bytes -- encoding )
{
{ [ dup HEX{ 0000FEFF } head? ] [ drop utf32be ] }
{ [ dup HEX{ FFFE0000 } head? ] [ drop utf32le ] }
{ [ dup HEX{ FEFF } head? ] [ drop utf16be ] }
{ [ dup HEX{ FFFE } head? ] [ drop utf16le ] }
{ [ dup HEX{ EF BB BF } head? ] [ drop utf8 ] }
{ [ dup $[ "<?xml" >byte-array ] head? ] [ detect-xml-prolog ] }
{ [ 0 over member? ] [ drop binary ] }
{ [ dup empty? ] [ drop utf8 ] }
{ [ dup valid-utf8? ] [ drop utf8 ] }
[ drop default-8bit-encoding get ]
} cond ;
: detect-stream ( stream -- sample encoding )
256 swap stream-read dup detect-byte-array ;
: detect-file ( file -- encoding )
binary [ input-stream get detect-stream nip ] with-file-reader ;

View File

@ -0,0 +1 @@
Heuristic auto-detection of text encodings and binary files

View File

@ -60,4 +60,11 @@ inline cell popcount(cell x)
return x;
}
inline bool bitmap_p(u8 *bitmap, cell index)
{
cell byte = index >> 3;
cell bit = index & 7;
return (bitmap[byte] & (1 << bit)) != 0;
}
}

View File

@ -35,16 +35,18 @@ void factor_vm::primitive_resize_byte_array()
ctx->push(tag<byte_array>(reallot_array(array.untagged(),capacity)));
}
void growable_byte_array::grow_bytes(cell len)
{
count += len;
if(count >= array_capacity(elements.untagged()))
elements = elements.parent->reallot_array(elements.untagged(),count * 2);
}
void growable_byte_array::append_bytes(void *elts, cell len)
{
cell new_size = count + len;
factor_vm *parent = elements.parent;
if(new_size >= array_capacity(elements.untagged()))
elements = parent->reallot_array(elements.untagged(),new_size * 2);
memcpy(&elements->data<u8>()[count],elts,len);
count += len;
cell old_count = count;
grow_bytes(len);
memcpy(&elements->data<u8>()[old_count],elts,len);
}
void growable_byte_array::append_byte_array(cell byte_array_)

View File

@ -7,6 +7,7 @@ struct growable_byte_array {
explicit growable_byte_array(factor_vm *parent,cell capacity = 40) : count(0), elements(parent->allot_byte_array(capacity),parent) { }
void grow_bytes(cell len);
void append_bytes(void *elts, cell len);
void append_byte_array(cell elts);

View File

@ -138,8 +138,10 @@ cell factor_vm::frame_scan(stack_frame *frame)
}
}
namespace
cell factor_vm::frame_offset(stack_frame *frame)
{
return (cell)FRAME_RETURN_ADDRESS(frame,this) - (cell)frame_code(frame)->entry_point();
}
struct stack_frame_accumulator {
factor_vm *parent;
@ -159,8 +161,6 @@ struct stack_frame_accumulator {
}
};
}
void factor_vm::primitive_callstack_to_array()
{
data_root<callstack> callstack(ctx->pop(),this);

View File

@ -12,12 +12,12 @@ Iteration is driven by visit_*() methods. Some of them define GC roots:
- visit_context_code_blocks()
- visit_callback_code_blocks() */
template<typename Visitor> struct code_block_visitor {
template<typename Fixup> struct code_block_visitor {
factor_vm *parent;
Visitor visitor;
Fixup fixup;
explicit code_block_visitor(factor_vm *parent_, Visitor visitor_) :
parent(parent_), visitor(visitor_) {}
explicit code_block_visitor(factor_vm *parent_, Fixup fixup_) :
parent(parent_), fixup(fixup_) {}
code_block *visit_code_block(code_block *compiled);
void visit_object_code_block(object *obj);
@ -26,33 +26,34 @@ template<typename Visitor> struct code_block_visitor {
void visit_uninitialized_code_blocks();
};
template<typename Visitor>
code_block *code_block_visitor<Visitor>::visit_code_block(code_block *compiled)
template<typename Fixup>
code_block *code_block_visitor<Fixup>::visit_code_block(code_block *compiled)
{
return visitor(compiled);
return fixup.fixup_code(compiled);
}
template<typename Visitor>
template<typename Fixup>
struct call_frame_code_block_visitor {
factor_vm *parent;
Visitor visitor;
Fixup fixup;
explicit call_frame_code_block_visitor(factor_vm *parent_, Visitor visitor_) :
parent(parent_), visitor(visitor_) {}
explicit call_frame_code_block_visitor(factor_vm *parent_, Fixup fixup_) :
parent(parent_), fixup(fixup_) {}
void operator()(stack_frame *frame)
{
cell offset = (cell)FRAME_RETURN_ADDRESS(frame,parent) - (cell)frame->entry_point;
code_block *old_block = parent->frame_code(frame);
cell offset = (char *)FRAME_RETURN_ADDRESS(frame,parent) - (char *)old_block;
code_block *new_block = visitor(parent->frame_code(frame));
const code_block *new_block = fixup.fixup_code(old_block);
frame->entry_point = new_block->entry_point();
FRAME_RETURN_ADDRESS(frame,parent) = (void *)((cell)frame->entry_point + offset);
FRAME_RETURN_ADDRESS(frame,parent) = (char *)new_block + offset;
}
};
template<typename Visitor>
void code_block_visitor<Visitor>::visit_object_code_block(object *obj)
template<typename Fixup>
void code_block_visitor<Fixup>::visit_object_code_block(object *obj)
{
switch(obj->type())
{
@ -60,9 +61,9 @@ void code_block_visitor<Visitor>::visit_object_code_block(object *obj)
{
word *w = (word *)obj;
if(w->code)
w->code = visitor(w->code);
w->code = visit_code_block(w->code);
if(w->profiling)
w->profiling = visitor(w->profiling);
w->profiling = visit_code_block(w->profiling);
parent->update_word_entry_point(w);
break;
@ -71,24 +72,24 @@ void code_block_visitor<Visitor>::visit_object_code_block(object *obj)
{
quotation *q = (quotation *)obj;
if(q->code)
parent->set_quot_entry_point(q,visitor(q->code));
parent->set_quot_entry_point(q,visit_code_block(q->code));
break;
}
case CALLSTACK_TYPE:
{
callstack *stack = (callstack *)obj;
call_frame_code_block_visitor<Visitor> call_frame_visitor(parent,visitor);
call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
parent->iterate_callstack_object(stack,call_frame_visitor);
break;
}
}
}
template<typename Visitor>
template<typename Fixup>
struct embedded_code_pointers_visitor {
Visitor visitor;
Fixup fixup;
explicit embedded_code_pointers_visitor(Visitor visitor_) : visitor(visitor_) {}
explicit embedded_code_pointers_visitor(Fixup fixup_) : fixup(fixup_) {}
void operator()(instruction_operand op)
{
@ -96,29 +97,29 @@ struct embedded_code_pointers_visitor {
if(type == RT_ENTRY_POINT
|| type == RT_ENTRY_POINT_PIC
|| type == RT_ENTRY_POINT_PIC_TAIL)
op.store_code_block(visitor(op.load_code_block()));
op.store_code_block(fixup.fixup_code(op.load_code_block()));
}
};
template<typename Visitor>
void code_block_visitor<Visitor>::visit_embedded_code_pointers(code_block *compiled)
template<typename Fixup>
void code_block_visitor<Fixup>::visit_embedded_code_pointers(code_block *compiled)
{
if(!parent->code->uninitialized_p(compiled))
{
embedded_code_pointers_visitor<Visitor> visitor(this->visitor);
compiled->each_instruction_operand(visitor);
embedded_code_pointers_visitor<Fixup> operand_visitor(fixup);
compiled->each_instruction_operand(operand_visitor);
}
}
template<typename Visitor>
void code_block_visitor<Visitor>::visit_context_code_blocks()
template<typename Fixup>
void code_block_visitor<Fixup>::visit_context_code_blocks()
{
call_frame_code_block_visitor<Visitor> call_frame_visitor(parent,visitor);
call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
parent->iterate_active_callstacks(call_frame_visitor);
}
template<typename Visitor>
void code_block_visitor<Visitor>::visit_uninitialized_code_blocks()
template<typename Fixup>
void code_block_visitor<Fixup>::visit_uninitialized_code_blocks()
{
std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks;
std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin();
@ -128,7 +129,7 @@ void code_block_visitor<Visitor>::visit_uninitialized_code_blocks()
for(; iter != end; iter++)
{
new_uninitialized_blocks.insert(std::make_pair(
visitor(iter->first),
fixup.fixup_code(iter->first),
iter->second));
}

View File

@ -43,11 +43,22 @@ struct code_block
return size;
}
template<typename Fixup> cell size(Fixup fixup) const
{
return size();
}
void *entry_point() const
{
return (void *)(this + 1);
}
/* GC info is stored at the end of the block */
gc_info *block_gc_info() const
{
return (gc_info *)((u8 *)this + size() - sizeof(gc_info));
}
void flush_icache()
{
factor::flush_icache((cell)this,size());

View File

@ -3,15 +3,17 @@ namespace factor
struct must_start_gc_again {};
template<typename TargetGeneration, typename Policy> struct data_workhorse {
template<typename TargetGeneration, typename Policy> struct gc_workhorse : no_fixup {
factor_vm *parent;
TargetGeneration *target;
Policy policy;
code_heap *code;
explicit data_workhorse(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
explicit gc_workhorse(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
parent(parent_),
target(target_),
policy(policy_) {}
policy(policy_),
code(parent->code) {}
object *resolve_forwarding(object *untagged)
{
@ -39,7 +41,7 @@ template<typename TargetGeneration, typename Policy> struct data_workhorse {
return newpointer;
}
object *operator()(object *obj)
object *fixup_data(object *obj)
{
if(!policy.should_copy_p(obj))
{
@ -59,17 +61,18 @@ template<typename TargetGeneration, typename Policy> struct data_workhorse {
return forwarding;
}
}
};
template<typename TargetGeneration, typename Policy>
inline static slot_visitor<data_workhorse<TargetGeneration,Policy> > make_data_visitor(
factor_vm *parent,
TargetGeneration *target,
Policy policy)
{
return slot_visitor<data_workhorse<TargetGeneration,Policy> >(parent,
data_workhorse<TargetGeneration,Policy>(parent,target,policy));
}
code_block *fixup_code(code_block *compiled)
{
if(!code->marked_p(compiled))
{
code->set_marked_p(compiled);
parent->mark_stack.push_back((cell)compiled + 1);
}
return compiled;
}
};
struct dummy_unmarker {
void operator()(card *ptr) {}
@ -92,7 +95,8 @@ struct collector {
data_heap *data;
code_heap *code;
TargetGeneration *target;
slot_visitor<data_workhorse<TargetGeneration,Policy> > data_visitor;
gc_workhorse<TargetGeneration,Policy> workhorse;
slot_visitor<gc_workhorse<TargetGeneration,Policy> > data_visitor;
cell cards_scanned;
cell decks_scanned;
cell code_blocks_scanned;
@ -102,7 +106,8 @@ struct collector {
data(parent_->data),
code(parent_->code),
target(target_),
data_visitor(make_data_visitor(parent_,target_,policy_)),
workhorse(parent,target,policy_),
data_visitor(parent,workhorse),
cards_scanned(0),
decks_scanned(0),
code_blocks_scanned(0) {}

View File

@ -2,105 +2,99 @@
namespace factor {
template<typename Block> struct forwarder {
mark_bits<Block> *forwarding_map;
struct compaction_fixup {
mark_bits<object> *data_forwarding_map;
mark_bits<code_block> *code_forwarding_map;
const object **data_finger;
const code_block **code_finger;
explicit forwarder(mark_bits<Block> *forwarding_map_) :
forwarding_map(forwarding_map_) {}
explicit compaction_fixup(
mark_bits<object> *data_forwarding_map_,
mark_bits<code_block> *code_forwarding_map_,
const object **data_finger_,
const code_block **code_finger_) :
data_forwarding_map(data_forwarding_map_),
code_forwarding_map(code_forwarding_map_),
data_finger(data_finger_),
code_finger(code_finger_) {}
Block *operator()(Block *block)
object *fixup_data(object *obj)
{
return forwarding_map->forward_block(block);
}
};
static inline cell tuple_size_with_forwarding(mark_bits<object> *forwarding_map, object *obj)
{
/* The tuple layout may or may not have been forwarded already. Tricky. */
object *layout_obj = (object *)UNTAG(((tuple *)obj)->layout);
tuple_layout *layout;
if(layout_obj < obj)
{
/* It's already been moved up; dereference through forwarding
map to get the size */
layout = (tuple_layout *)forwarding_map->forward_block(layout_obj);
}
else
{
/* It hasn't been moved up yet; dereference directly */
layout = (tuple_layout *)layout_obj;
return data_forwarding_map->forward_block(obj);
}
return tuple_size(layout);
}
struct compaction_sizer {
mark_bits<object> *forwarding_map;
explicit compaction_sizer(mark_bits<object> *forwarding_map_) :
forwarding_map(forwarding_map_) {}
cell operator()(object *obj)
code_block *fixup_code(code_block *compiled)
{
if(!forwarding_map->marked_p(obj))
return forwarding_map->unmarked_block_size(obj);
else if(obj->type() == TUPLE_TYPE)
return align(tuple_size_with_forwarding(forwarding_map,obj),data_alignment);
return code_forwarding_map->forward_block(compiled);
}
object *translate_data(const object *obj)
{
if(obj < *data_finger)
return fixup_data((object *)obj);
else
return obj->size();
return (object *)obj;
}
code_block *translate_code(const code_block *compiled)
{
if(compiled < *code_finger)
return fixup_code((code_block *)compiled);
else
return (code_block *)compiled;
}
cell size(object *obj)
{
if(data_forwarding_map->marked_p(obj))
return obj->size(*this);
else
return data_forwarding_map->unmarked_block_size(obj);
}
cell size(code_block *compiled)
{
if(code_forwarding_map->marked_p(compiled))
return compiled->size(*this);
else
return code_forwarding_map->unmarked_block_size(compiled);
}
};
struct object_compaction_updater {
factor_vm *parent;
mark_bits<code_block> *code_forwarding_map;
mark_bits<object> *data_forwarding_map;
compaction_fixup fixup;
object_start_map *starts;
explicit object_compaction_updater(factor_vm *parent_,
mark_bits<object> *data_forwarding_map_,
mark_bits<code_block> *code_forwarding_map_) :
explicit object_compaction_updater(factor_vm *parent_, compaction_fixup fixup_) :
parent(parent_),
code_forwarding_map(code_forwarding_map_),
data_forwarding_map(data_forwarding_map_),
fixup(fixup_),
starts(&parent->data->tenured->starts) {}
void operator()(object *old_address, object *new_address, cell size)
{
cell payload_start;
if(old_address->type() == TUPLE_TYPE)
payload_start = tuple_size_with_forwarding(data_forwarding_map,old_address);
else
payload_start = old_address->binary_payload_start();
slot_visitor<compaction_fixup> slot_forwarder(parent,fixup);
slot_forwarder.visit_slots(new_address);
memmove(new_address,old_address,size);
slot_visitor<forwarder<object> > slot_forwarder(parent,forwarder<object>(data_forwarding_map));
slot_forwarder.visit_slots(new_address,payload_start);
code_block_visitor<forwarder<code_block> > code_forwarder(parent,forwarder<code_block>(code_forwarding_map));
code_block_visitor<compaction_fixup> code_forwarder(parent,fixup);
code_forwarder.visit_object_code_block(new_address);
starts->record_object_start_offset(new_address);
}
};
template<typename SlotForwarder>
template<typename Fixup>
struct code_block_compaction_relocation_visitor {
factor_vm *parent;
code_block *old_address;
slot_visitor<SlotForwarder> slot_forwarder;
code_block_visitor<forwarder<code_block> > code_forwarder;
Fixup fixup;
explicit code_block_compaction_relocation_visitor(factor_vm *parent_,
code_block *old_address_,
slot_visitor<SlotForwarder> slot_forwarder_,
code_block_visitor<forwarder<code_block> > code_forwarder_) :
Fixup fixup_) :
parent(parent_),
old_address(old_address_),
slot_forwarder(slot_forwarder_),
code_forwarder(code_forwarder_) {}
fixup(fixup_) {}
void operator()(instruction_operand op)
{
@ -109,16 +103,25 @@ struct code_block_compaction_relocation_visitor {
switch(op.rel_type())
{
case RT_LITERAL:
op.store_value(slot_forwarder.visit_pointer(op.load_value(old_offset)));
break;
{
cell value = op.load_value(old_offset);
if(immediate_p(value))
op.store_value(value);
else
op.store_value(RETAG(fixup.fixup_data(untag<object>(value)),TAG(value)));
break;
}
case RT_ENTRY_POINT:
case RT_ENTRY_POINT_PIC:
case RT_ENTRY_POINT_PIC_TAIL:
op.store_code_block(code_forwarder.visit_code_block(op.load_code_block(old_offset)));
break;
case RT_HERE:
op.store_value(op.load_value(old_offset) - (cell)old_address + (cell)op.parent_code_block());
break;
{
cell value = op.load_value(old_offset);
cell offset = TAG(value);
code_block *compiled = (code_block *)UNTAG(value);
op.store_value((cell)fixup.fixup_code(compiled) + offset);
break;
}
case RT_THIS:
case RT_CARDS_OFFSET:
case RT_DECKS_OFFSET:
@ -131,26 +134,27 @@ struct code_block_compaction_relocation_visitor {
}
};
template<typename SlotForwarder>
template<typename Fixup>
struct code_block_compaction_updater {
factor_vm *parent;
slot_visitor<SlotForwarder> slot_forwarder;
code_block_visitor<forwarder<code_block> > code_forwarder;
Fixup fixup;
slot_visitor<Fixup> data_forwarder;
code_block_visitor<Fixup> code_forwarder;
explicit code_block_compaction_updater(factor_vm *parent_,
slot_visitor<SlotForwarder> slot_forwarder_,
code_block_visitor<forwarder<code_block> > code_forwarder_) :
Fixup fixup_,
slot_visitor<Fixup> data_forwarder_,
code_block_visitor<Fixup> code_forwarder_) :
parent(parent_),
slot_forwarder(slot_forwarder_),
fixup(fixup_),
data_forwarder(data_forwarder_),
code_forwarder(code_forwarder_) {}
void operator()(code_block *old_address, code_block *new_address, cell size)
{
memmove(new_address,old_address,size);
data_forwarder.visit_code_block_objects(new_address);
slot_forwarder.visit_code_block_objects(new_address);
code_block_compaction_relocation_visitor<SlotForwarder> visitor(parent,old_address,slot_forwarder,code_forwarder);
code_block_compaction_relocation_visitor<Fixup> visitor(parent,old_address,fixup);
new_address->each_instruction_operand(visitor);
}
};
@ -196,8 +200,12 @@ void factor_vm::collect_compact_impl(bool trace_contexts_p)
data_forwarding_map->compute_forwarding();
code_forwarding_map->compute_forwarding();
slot_visitor<forwarder<object> > slot_forwarder(this,forwarder<object>(data_forwarding_map));
code_block_visitor<forwarder<code_block> > code_forwarder(this,forwarder<code_block>(code_forwarding_map));
const object *data_finger = tenured->first_block();
const code_block *code_finger = code->allocator->first_block();
compaction_fixup fixup(data_forwarding_map,code_forwarding_map,&data_finger,&code_finger);
slot_visitor<compaction_fixup> data_forwarder(this,fixup);
code_block_visitor<compaction_fixup> code_forwarder(this,fixup);
code_forwarder.visit_uninitialized_code_blocks();
@ -206,20 +214,18 @@ void factor_vm::collect_compact_impl(bool trace_contexts_p)
/* Slide everything in tenured space up, and update data and code heap
pointers inside objects. */
object_compaction_updater object_updater(this,data_forwarding_map,code_forwarding_map);
compaction_sizer object_sizer(data_forwarding_map);
tenured->compact(object_updater,object_sizer);
object_compaction_updater object_updater(this,fixup);
tenured->compact(object_updater,fixup,&data_finger);
/* Slide everything in the code heap up, and update data and code heap
pointers inside code blocks. */
code_block_compaction_updater<forwarder<object> > code_block_updater(this,slot_forwarder,code_forwarder);
standard_sizer<code_block> code_block_sizer;
code->allocator->compact(code_block_updater,code_block_sizer);
code_block_compaction_updater<compaction_fixup> code_block_updater(this,fixup,data_forwarder,code_forwarder);
code->allocator->compact(code_block_updater,fixup,&code_finger);
slot_forwarder.visit_roots();
data_forwarder.visit_roots();
if(trace_contexts_p)
{
slot_forwarder.visit_contexts();
data_forwarder.visit_contexts();
code_forwarder.visit_context_code_blocks();
}
@ -229,10 +235,56 @@ void factor_vm::collect_compact_impl(bool trace_contexts_p)
current_gc->event->ended_compaction();
}
struct object_grow_heap_updater {
code_block_visitor<forwarder<code_block> > code_forwarder;
struct code_compaction_fixup {
mark_bits<code_block> *code_forwarding_map;
const code_block **code_finger;
explicit object_grow_heap_updater(code_block_visitor<forwarder<code_block> > code_forwarder_) :
explicit code_compaction_fixup(mark_bits<code_block> *code_forwarding_map_,
const code_block **code_finger_) :
code_forwarding_map(code_forwarding_map_),
code_finger(code_finger_) {}
object *fixup_data(object *obj)
{
return obj;
}
code_block *fixup_code(code_block *compiled)
{
return code_forwarding_map->forward_block(compiled);
}
object *translate_data(const object *obj)
{
return fixup_data((object *)obj);
}
code_block *translate_code(const code_block *compiled)
{
if(compiled >= *code_finger)
return fixup_code((code_block *)compiled);
else
return (code_block *)compiled;
}
cell size(object *obj)
{
return obj->size();
}
cell size(code_block *compiled)
{
if(code_forwarding_map->marked_p(compiled))
return compiled->size(*this);
else
return code_forwarding_map->unmarked_block_size(compiled);
}
};
struct object_grow_heap_updater {
code_block_visitor<code_compaction_fixup> code_forwarder;
explicit object_grow_heap_updater(code_block_visitor<code_compaction_fixup> code_forwarder_) :
code_forwarder(code_forwarder_) {}
void operator()(object *obj)
@ -241,10 +293,6 @@ struct object_grow_heap_updater {
}
};
struct dummy_slot_forwarder {
object *operator()(object *obj) { return obj; }
};
/* Compact just the code heap, after growing the data heap */
void factor_vm::collect_compact_code_impl(bool trace_contexts_p)
{
@ -252,8 +300,11 @@ void factor_vm::collect_compact_code_impl(bool trace_contexts_p)
mark_bits<code_block> *code_forwarding_map = &code->allocator->state;
code_forwarding_map->compute_forwarding();
slot_visitor<dummy_slot_forwarder> slot_forwarder(this,dummy_slot_forwarder());
code_block_visitor<forwarder<code_block> > code_forwarder(this,forwarder<code_block>(code_forwarding_map));
const code_block *code_finger = code->allocator->first_block();
code_compaction_fixup fixup(code_forwarding_map,&code_finger);
slot_visitor<code_compaction_fixup> data_forwarder(this,fixup);
code_block_visitor<code_compaction_fixup> code_forwarder(this,fixup);
code_forwarder.visit_uninitialized_code_blocks();
@ -261,14 +312,13 @@ void factor_vm::collect_compact_code_impl(bool trace_contexts_p)
code_forwarder.visit_context_code_blocks();
/* Update code heap references in data heap */
object_grow_heap_updater updater(code_forwarder);
each_object(updater);
object_grow_heap_updater object_updater(code_forwarder);
each_object(object_updater);
/* Slide everything in the code heap up, and update code heap
pointers inside code blocks. */
code_block_compaction_updater<dummy_slot_forwarder> code_block_updater(this,slot_forwarder,code_forwarder);
standard_sizer<code_block> code_block_sizer;
code->allocator->compact(code_block_updater,code_block_sizer);
code_block_compaction_updater<code_compaction_fixup> code_block_updater(this,fixup,data_forwarder,code_forwarder);
code->allocator->compact(code_block_updater,fixup,&code_finger);
update_code_roots_for_compaction();
callbacks->update();

View File

@ -55,6 +55,31 @@ void context::fix_stacks()
reset_retainstack();
}
void context::scrub_stacks(gc_info *info, cell index)
{
u8 *bitmap = info->gc_info_bitmap();
{
cell base = info->scrub_d_base(index);
for(cell loc = 0; loc < info->scrub_d_count; loc++)
{
if(bitmap_p(bitmap,base + loc))
((cell *)datastack)[-loc] = 0;
}
}
{
cell base = info->scrub_r_base(index);
for(cell loc = 0; loc < info->scrub_r_count; loc++)
{
if(bitmap_p(bitmap,base + loc))
((cell *)retainstack)[-loc] = 0;
}
}
}
context::~context()
{
delete datastack_seg;

View File

@ -45,6 +45,7 @@ struct context {
void reset_context_objects();
void reset();
void fix_stacks();
void scrub_stacks(gc_info *info, cell index);
cell peek()
{

View File

@ -126,85 +126,6 @@ void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_si
set_data_heap(new data_heap(young_size,aging_size,tenured_size));
}
/* Size of the object pointed to by an untagged pointer */
cell object::size() const
{
if(free_p()) return ((free_heap_block *)this)->size();
switch(type())
{
case ARRAY_TYPE:
return align(array_size((array*)this),data_alignment);
case BIGNUM_TYPE:
return align(array_size((bignum*)this),data_alignment);
case BYTE_ARRAY_TYPE:
return align(array_size((byte_array*)this),data_alignment);
case STRING_TYPE:
return align(string_size(string_capacity((string*)this)),data_alignment);
case TUPLE_TYPE:
{
tuple_layout *layout = (tuple_layout *)UNTAG(((tuple *)this)->layout);
return align(tuple_size(layout),data_alignment);
}
case QUOTATION_TYPE:
return align(sizeof(quotation),data_alignment);
case WORD_TYPE:
return align(sizeof(word),data_alignment);
case FLOAT_TYPE:
return align(sizeof(boxed_float),data_alignment);
case DLL_TYPE:
return align(sizeof(dll),data_alignment);
case ALIEN_TYPE:
return align(sizeof(alien),data_alignment);
case WRAPPER_TYPE:
return align(sizeof(wrapper),data_alignment);
case CALLSTACK_TYPE:
return align(callstack_object_size(untag_fixnum(((callstack *)this)->length)),data_alignment);
default:
critical_error("Invalid header",(cell)this);
return 0; /* can't happen */
}
}
/* The number of cells from the start of the object which should be scanned by
the GC. Some types have a binary payload at the end (string, word, DLL) which
we ignore. */
cell object::binary_payload_start() const
{
if(free_p()) return 0;
switch(type())
{
/* these objects do not refer to other objects at all */
case FLOAT_TYPE:
case BYTE_ARRAY_TYPE:
case BIGNUM_TYPE:
case CALLSTACK_TYPE:
return 0;
/* these objects have some binary data at the end */
case WORD_TYPE:
return sizeof(word) - sizeof(cell) * 3;
case ALIEN_TYPE:
return sizeof(cell) * 3;
case DLL_TYPE:
return sizeof(cell) * 2;
case QUOTATION_TYPE:
return sizeof(quotation) - sizeof(cell) * 2;
case STRING_TYPE:
return sizeof(string);
/* everything else consists entirely of pointers */
case ARRAY_TYPE:
return array_size<array>(array_capacity((array*)this));
case TUPLE_TYPE:
return tuple_size(untag<tuple_layout>(((tuple *)this)->layout));
case WRAPPER_TYPE:
return sizeof(wrapper);
default:
critical_error("Invalid header",(cell)this);
return 0; /* can't happen */
}
}
data_heap_room factor_vm::data_room()
{
data_heap_room room;

44
vm/fixup.hpp Normal file
View File

@ -0,0 +1,44 @@
namespace factor
{
template<typename T>
struct identity {
T operator()(T t)
{
return t;
}
};
struct no_fixup {
object *fixup_data(object *obj)
{
return obj;
}
code_block *fixup_code(code_block *compiled)
{
return compiled;
}
object *translate_data(const object *obj)
{
return fixup_data((object *)obj);
}
code_block *translate_code(const code_block *compiled)
{
return fixup_code((code_block *)compiled);
}
cell size(object *obj)
{
return obj->size();
}
cell size(code_block *compiled)
{
return compiled->size();
}
};
}

View File

@ -23,8 +23,8 @@ template<typename Block> struct free_list_allocator {
cell largest_free_block();
cell free_block_count();
void sweep();
template<typename Iterator, typename Sizer> void compact(Iterator &iter, Sizer &sizer);
template<typename Iterator, typename Sizer> void iterate(Iterator &iter, Sizer &sizer);
template<typename Iterator, typename Fixup> void compact(Iterator &iter, Fixup fixup, const Block **finger);
template<typename Iterator, typename Fixup> void iterate(Iterator &iter, Fixup fixup);
template<typename Iterator> void iterate(Iterator &iter);
};
@ -155,14 +155,17 @@ template<typename Block, typename Iterator> struct heap_compactor {
mark_bits<Block> *state;
char *address;
Iterator &iter;
const Block **finger;
explicit heap_compactor(mark_bits<Block> *state_, Block *address_, Iterator &iter_) :
state(state_), address((char *)address_), iter(iter_) {}
explicit heap_compactor(mark_bits<Block> *state_, Block *address_, Iterator &iter_, const Block **finger_) :
state(state_), address((char *)address_), iter(iter_), finger(finger_) {}
void operator()(Block *block, cell size)
{
if(this->state->marked_p(block))
{
*finger = block;
memmove((Block *)address,block,size);
iter(block,(Block *)address,size);
address += size;
}
@ -172,11 +175,11 @@ template<typename Block, typename Iterator> struct heap_compactor {
/* The forwarding map must be computed first by calling
state.compute_forwarding(). */
template<typename Block>
template<typename Iterator, typename Sizer>
void free_list_allocator<Block>::compact(Iterator &iter, Sizer &sizer)
template<typename Iterator, typename Fixup>
void free_list_allocator<Block>::compact(Iterator &iter, Fixup fixup, const Block **finger)
{
heap_compactor<Block,Iterator> compactor(&state,first_block(),iter);
iterate(compactor,sizer);
heap_compactor<Block,Iterator> compactor(&state,first_block(),iter,finger);
iterate(compactor,fixup);
/* Now update the free list; there will be a single free block at
the end */
@ -185,34 +188,26 @@ void free_list_allocator<Block>::compact(Iterator &iter, Sizer &sizer)
/* During compaction we have to be careful and measure object sizes differently */
template<typename Block>
template<typename Iterator, typename Sizer>
void free_list_allocator<Block>::iterate(Iterator &iter, Sizer &sizer)
template<typename Iterator, typename Fixup>
void free_list_allocator<Block>::iterate(Iterator &iter, Fixup fixup)
{
Block *scan = first_block();
Block *end = last_block();
while(scan != end)
{
cell size = sizer(scan);
cell size = fixup.size(scan);
Block *next = (Block *)((cell)scan + size);
if(!scan->free_p()) iter(scan,size);
scan = next;
}
}
template<typename Block> struct standard_sizer {
cell operator()(Block *block)
{
return block->size();
}
};
template<typename Block>
template<typename Iterator>
void free_list_allocator<Block>::iterate(Iterator &iter)
{
standard_sizer<Block> sizer;
iterate(iter,sizer);
iterate(iter,no_fixup());
}
}

View File

@ -3,17 +3,9 @@
namespace factor
{
inline static code_block_visitor<code_workhorse> make_code_visitor(factor_vm *parent)
{
return code_block_visitor<code_workhorse>(parent,code_workhorse(parent));
}
full_collector::full_collector(factor_vm *parent_) :
collector<tenured_space,full_policy>(
parent_,
parent_->data->tenured,
full_policy(parent_)),
code_visitor(make_code_visitor(parent_)) {}
collector<tenured_space,full_policy>(parent_,parent_->data->tenured,full_policy(parent_)),
code_visitor(parent,workhorse) {}
void full_collector::trace_code_block(code_block *compiled)
{

View File

@ -25,26 +25,8 @@ struct full_policy {
}
};
struct code_workhorse {
factor_vm *parent;
code_heap *code;
explicit code_workhorse(factor_vm *parent_) : parent(parent_), code(parent->code) {}
code_block *operator()(code_block *compiled)
{
if(!code->marked_p(compiled))
{
code->set_marked_p(compiled);
parent->mark_stack.push_back((cell)compiled + 1);
}
return compiled;
}
};
struct full_collector : collector<tenured_space,full_policy> {
code_block_visitor<code_workhorse> code_visitor;
code_block_visitor<gc_workhorse<tenured_space,full_policy> > code_visitor;
explicit full_collector(factor_vm *parent_);
void trace_code_block(code_block *compiled);

View File

@ -194,8 +194,52 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
current_gc = NULL;
}
/* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
uninitialized stack locations before actually calling the GC. See the comment
in compiler.cfg.stacks.uninitialized for details. */
struct call_frame_scrubber {
factor_vm *parent;
context *ctx;
explicit call_frame_scrubber(factor_vm *parent_, context *ctx_) :
parent(parent_), ctx(ctx_) {}
void operator()(stack_frame *frame)
{
const code_block *compiled = parent->frame_code(frame);
gc_info *info = compiled->block_gc_info();
cell return_address = parent->frame_offset(frame);
assert(return_address < compiled->size());
int index = info->return_address_index(return_address);
if(index != -1)
ctx->scrub_stacks(info,index);
}
};
void factor_vm::scrub_context(context *ctx)
{
call_frame_scrubber scrubber(this,ctx);
iterate_callstack(ctx,scrubber);
}
void factor_vm::scrub_contexts()
{
std::set<context *>::const_iterator begin = active_contexts.begin();
std::set<context *>::const_iterator end = active_contexts.end();
while(begin != end)
{
scrub_context(*begin);
begin++;
}
}
void factor_vm::primitive_minor_gc()
{
scrub_contexts();
gc(collect_nursery_op,
0, /* requested size */
true /* trace contexts? */);
@ -215,36 +259,6 @@ void factor_vm::primitive_compact_gc()
true /* trace contexts? */);
}
void factor_vm::inline_gc(cell gc_roots_)
{
cell stack_pointer = (cell)ctx->callstack_top;
if(to_boolean(gc_roots_))
{
tagged<array> gc_roots(gc_roots_);
cell capacity = array_capacity(gc_roots.untagged());
for(cell i = 0; i < capacity; i++)
{
cell spill_slot = untag_fixnum(array_nth(gc_roots.untagged(),i));
cell *address = (cell *)(spill_slot + stack_pointer);
data_roots.push_back(data_root_range(address,1));
}
primitive_minor_gc();
for(cell i = 0; i < capacity; i++)
data_roots.pop_back();
}
else
primitive_minor_gc();
}
VM_C_API void inline_gc(cell gc_roots, factor_vm *parent)
{
parent->inline_gc(gc_roots);
}
/*
* It is up to the caller to fill in the object's fields in a meaningful
* fashion!

View File

@ -52,6 +52,4 @@ struct gc_state {
void start_again(gc_op op_, factor_vm *parent);
};
VM_C_API void inline_gc(cell gc_roots, factor_vm *parent);
}

19
vm/gc_info.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "master.hpp"
namespace factor
{
int gc_info::return_address_index(cell return_address)
{
u32 *return_address_array = return_addresses();
for(cell i = 0; i < return_address_count; i++)
{
if(return_address == return_address_array[i])
return i;
}
return -1;
}
}

51
vm/gc_info.hpp Normal file
View File

@ -0,0 +1,51 @@
namespace factor
{
struct gc_info {
u32 scrub_d_count;
u32 scrub_r_count;
u32 gc_root_count;
u32 return_address_count;
cell total_bitmap_size()
{
return return_address_count * (scrub_d_count + scrub_r_count + gc_root_count);
}
cell total_bitmap_bytes()
{
return ((total_bitmap_size() + 7) / 8);
}
u32 *return_addresses()
{
return (u32 *)((u8 *)this - return_address_count * sizeof(u32));
}
u8 *gc_info_bitmap()
{
return (u8 *)return_addresses() - total_bitmap_bytes();
}
cell scrub_d_base(cell index)
{
return index * scrub_d_count;
}
cell scrub_r_base(cell index)
{
return return_address_count * scrub_d_count +
index * scrub_r_count;
}
cell spill_slot_base(cell index)
{
return return_address_count * scrub_d_count
+ return_address_count * scrub_r_count
+ index * gc_root_count;
}
int return_address_index(cell return_address);
};
}

View File

@ -55,70 +55,66 @@ void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p)
code->allocator->initial_free_list(h->code_size);
}
struct data_fixupper {
cell offset;
explicit data_fixupper(cell offset_) : offset(offset_) {}
object *operator()(object *obj)
{
return (object *)((char *)obj + offset);
}
};
struct code_fixupper {
cell offset;
explicit code_fixupper(cell offset_) : offset(offset_) {}
code_block *operator()(code_block *compiled)
{
return (code_block *)((char *)compiled + offset);
}
};
static inline cell tuple_size_with_fixup(cell offset, object *obj)
{
tuple_layout *layout = (tuple_layout *)((char *)UNTAG(((tuple *)obj)->layout) + offset);
return tuple_size(layout);
}
struct fixup_sizer {
cell offset;
explicit fixup_sizer(cell offset_) : offset(offset_) {}
cell operator()(object *obj)
{
if(obj->type() == TUPLE_TYPE)
return align(tuple_size_with_fixup(offset,obj),data_alignment);
else
return obj->size();
}
};
struct object_fixupper {
factor_vm *parent;
struct startup_fixup {
cell data_offset;
slot_visitor<data_fixupper> data_visitor;
code_block_visitor<code_fixupper> code_visitor;
cell code_offset;
object_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) :
explicit startup_fixup(cell data_offset_, cell code_offset_) :
data_offset(data_offset_), code_offset(code_offset_) {}
object *fixup_data(object *obj)
{
return (object *)((cell)obj + data_offset);
}
code_block *fixup_code(code_block *obj)
{
return (code_block *)((cell)obj + code_offset);
}
object *translate_data(const object *obj)
{
return fixup_data((object *)obj);
}
code_block *translate_code(const code_block *compiled)
{
return fixup_code((code_block *)compiled);
}
cell size(const object *obj)
{
return obj->size(*this);
}
cell size(code_block *compiled)
{
return compiled->size(*this);
}
};
struct start_object_updater {
factor_vm *parent;
startup_fixup fixup;
slot_visitor<startup_fixup> data_visitor;
code_block_visitor<startup_fixup> code_visitor;
start_object_updater(factor_vm *parent_, startup_fixup fixup_) :
parent(parent_),
data_offset(data_offset_),
data_visitor(slot_visitor<data_fixupper>(parent_,data_fixupper(data_offset_))),
code_visitor(code_block_visitor<code_fixupper>(parent_,code_fixupper(code_offset_))) {}
fixup(fixup_),
data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)),
code_visitor(code_block_visitor<startup_fixup>(parent_,fixup_)) {}
void operator()(object *obj, cell size)
{
parent->data->tenured->starts.record_object_start_offset(obj);
data_visitor.visit_slots(obj);
switch(obj->type())
{
case ALIEN_TYPE:
{
cell payload_start = obj->binary_payload_start();
data_visitor.visit_slots(obj,payload_start);
alien *ptr = (alien *)obj;
@ -130,22 +126,11 @@ struct object_fixupper {
}
case DLL_TYPE:
{
cell payload_start = obj->binary_payload_start();
data_visitor.visit_slots(obj,payload_start);
parent->ffi_dlopen((dll *)obj);
break;
}
case TUPLE_TYPE:
{
cell payload_start = tuple_size_with_fixup(data_offset,obj);
data_visitor.visit_slots(obj,payload_start);
break;
}
default:
{
cell payload_start = obj->binary_payload_start();
data_visitor.visit_slots(obj,payload_start);
code_visitor.visit_object_code_block(obj);
break;
}
@ -155,44 +140,51 @@ struct object_fixupper {
void factor_vm::fixup_data(cell data_offset, cell code_offset)
{
slot_visitor<data_fixupper> data_workhorse(this,data_fixupper(data_offset));
startup_fixup fixup(data_offset,code_offset);
slot_visitor<startup_fixup> data_workhorse(this,fixup);
data_workhorse.visit_roots();
object_fixupper fixupper(this,data_offset,code_offset);
fixup_sizer sizer(data_offset);
data->tenured->iterate(fixupper,sizer);
start_object_updater updater(this,fixup);
data->tenured->iterate(updater,fixup);
}
struct code_block_fixup_relocation_visitor {
struct startup_code_block_relocation_visitor {
factor_vm *parent;
cell code_offset;
slot_visitor<data_fixupper> data_visitor;
code_fixupper code_visitor;
startup_fixup fixup;
slot_visitor<startup_fixup> data_visitor;
code_block_fixup_relocation_visitor(factor_vm *parent_, cell data_offset_, cell code_offset_) :
startup_code_block_relocation_visitor(factor_vm *parent_, startup_fixup fixup_) :
parent(parent_),
code_offset(code_offset_),
data_visitor(slot_visitor<data_fixupper>(parent_,data_fixupper(data_offset_))),
code_visitor(code_fixupper(code_offset_)) {}
fixup(fixup_),
data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)) {}
void operator()(instruction_operand op)
{
code_block *compiled = op.parent_code_block();
cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - code_offset;
cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - fixup.code_offset;
switch(op.rel_type())
{
case RT_LITERAL:
op.store_value(data_visitor.visit_pointer(op.load_value(old_offset)));
break;
{
cell value = op.load_value(old_offset);
if(immediate_p(value))
op.store_value(value);
else
op.store_value(RETAG(fixup.fixup_data(untag<object>(value)),TAG(value)));
break;
}
case RT_ENTRY_POINT:
case RT_ENTRY_POINT_PIC:
case RT_ENTRY_POINT_PIC_TAIL:
op.store_code_block(code_visitor(op.load_code_block(old_offset)));
break;
case RT_HERE:
op.store_value(op.load_value(old_offset) + code_offset);
break;
{
cell value = op.load_value(old_offset);
cell offset = TAG(value);
code_block *compiled = (code_block *)UNTAG(value);
op.store_value((cell)fixup.fixup_code(compiled) + offset);
break;
}
case RT_UNTAGGED:
break;
default:
@ -202,30 +194,28 @@ struct code_block_fixup_relocation_visitor {
}
};
struct code_block_fixupper {
struct startup_code_block_updater {
factor_vm *parent;
cell data_offset;
cell code_offset;
startup_fixup fixup;
code_block_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) :
parent(parent_),
data_offset(data_offset_),
code_offset(code_offset_) {}
startup_code_block_updater(factor_vm *parent_, startup_fixup fixup_) :
parent(parent_), fixup(fixup_) {}
void operator()(code_block *compiled, cell size)
{
slot_visitor<data_fixupper> data_visitor(parent,data_fixupper(data_offset));
slot_visitor<startup_fixup> data_visitor(parent,fixup);
data_visitor.visit_code_block_objects(compiled);
code_block_fixup_relocation_visitor code_visitor(parent,data_offset,code_offset);
startup_code_block_relocation_visitor code_visitor(parent,fixup);
compiled->each_instruction_operand(code_visitor);
}
};
void factor_vm::fixup_code(cell data_offset, cell code_offset)
{
code_block_fixupper fixupper(this,data_offset,code_offset);
code->allocator->iterate(fixupper);
startup_fixup fixup(data_offset,code_offset);
startup_code_block_updater updater(this,fixup);
code->allocator->iterate(updater,fixup);
}
/* Read an image file from disk, only done once during startup */

View File

@ -116,6 +116,11 @@ void jit::compute_position(cell offset_)
/* Allocates memory */
code_block *jit::to_code_block()
{
/* Emit dummy GC info */
code.grow_bytes(alignment_for(code.count + 4,data_alignment));
u32 dummy_gc_info = 0;
code.append_bytes(&dummy_gc_info,sizeof(u32));
code.trim();
relocation.trim();
parameters.trim();

View File

@ -23,6 +23,11 @@ inline static cell align(cell a, cell b)
return (a + (b-1)) & ~(b-1);
}
inline static cell alignment_for(cell a, cell b)
{
return align(a,b) - a;
}
static const cell data_alignment = 16;
#define WORD_SIZE (signed)(sizeof(cell)*8)
@ -98,7 +103,10 @@ struct object {
cell header;
cell size() const;
template<typename Fixup> cell size(Fixup fixup) const;
cell binary_payload_start() const;
template<typename Fixup> cell binary_payload_start(Fixup fixup) const;
cell *slots() const { return (cell *)this; }

View File

@ -40,7 +40,7 @@ template<typename Block> struct mark_bits {
forwarding = NULL;
}
cell block_line(Block *address)
cell block_line(const Block *address)
{
return (((cell)address - start) / data_alignment);
}
@ -50,7 +50,7 @@ template<typename Block> struct mark_bits {
return (Block *)(line * data_alignment + start);
}
std::pair<cell,cell> bitmap_deref(Block *address)
std::pair<cell,cell> bitmap_deref(const Block *address)
{
cell line_number = block_line(address);
cell word_index = (line_number / mark_bits_granularity);
@ -58,18 +58,18 @@ template<typename Block> struct mark_bits {
return std::make_pair(word_index,word_shift);
}
bool bitmap_elt(cell *bits, Block *address)
bool bitmap_elt(cell *bits, const Block *address)
{
std::pair<cell,cell> position = bitmap_deref(address);
return (bits[position.first] & ((cell)1 << position.second)) != 0;
}
Block *next_block_after(Block *block)
Block *next_block_after(const Block *block)
{
return (Block *)((cell)block + block->size());
}
void set_bitmap_range(cell *bits, Block *address)
void set_bitmap_range(cell *bits, const Block *address)
{
std::pair<cell,cell> start = bitmap_deref(address);
std::pair<cell,cell> end = bitmap_deref(next_block_after(address));
@ -99,12 +99,12 @@ template<typename Block> struct mark_bits {
}
}
bool marked_p(Block *address)
bool marked_p(const Block *address)
{
return bitmap_elt(marked,address);
}
void set_marked_p(Block *address)
void set_marked_p(const Block *address)
{
set_bitmap_range(marked,address);
}
@ -123,7 +123,7 @@ template<typename Block> struct mark_bits {
/* We have the popcount for every mark_bits_granularity entries; look
up and compute the rest */
Block *forward_block(Block *original)
Block *forward_block(const Block *original)
{
#ifdef FACTOR_DEBUG
assert(marked_p(original));
@ -141,7 +141,7 @@ template<typename Block> struct mark_bits {
return new_block;
}
Block *next_unmarked_block_after(Block *original)
Block *next_unmarked_block_after(const Block *original)
{
std::pair<cell,cell> position = bitmap_deref(original);
cell bit_index = position.second;
@ -168,7 +168,7 @@ template<typename Block> struct mark_bits {
return (Block *)(this->start + this->size);
}
Block *next_marked_block_after(Block *original)
Block *next_marked_block_after(const Block *original)
{
std::pair<cell,cell> position = bitmap_deref(original);
cell bit_index = position.second;

View File

@ -75,6 +75,7 @@ namespace factor
#include "platform.hpp"
#include "primitives.hpp"
#include "segments.hpp"
#include "gc_info.hpp"
#include "contexts.hpp"
#include "run.hpp"
#include "objects.hpp"
@ -89,6 +90,8 @@ namespace factor
#include "bitwise_hacks.hpp"
#include "mark_bits.hpp"
#include "free_list.hpp"
#include "fixup.hpp"
#include "tuples.hpp"
#include "free_list_allocator.hpp"
#include "write_barrier.hpp"
#include "object_start_map.hpp"
@ -100,7 +103,6 @@ namespace factor
#include "gc.hpp"
#include "debug.hpp"
#include "strings.hpp"
#include "tuples.hpp"
#include "words.hpp"
#include "float_bits.hpp"
#include "io.hpp"
@ -115,6 +117,7 @@ namespace factor
#include "data_roots.hpp"
#include "code_roots.hpp"
#include "generic_arrays.hpp"
#include "callstack.hpp"
#include "slot_visitor.hpp"
#include "collector.hpp"
#include "copying_collector.hpp"
@ -124,7 +127,6 @@ namespace factor
#include "code_block_visitor.hpp"
#include "compaction.hpp"
#include "full_collector.hpp"
#include "callstack.hpp"
#include "arrays.hpp"
#include "math.hpp"
#include "byte_arrays.hpp"

View File

@ -82,13 +82,13 @@ void factor_vm::primitive_size()
ctx->push(allot_cell(object_size(ctx->pop())));
}
struct slot_become_visitor {
struct slot_become_fixup : no_fixup {
std::map<object *,object *> *become_map;
explicit slot_become_visitor(std::map<object *,object *> *become_map_) :
explicit slot_become_fixup(std::map<object *,object *> *become_map_) :
become_map(become_map_) {}
object *operator()(object *old)
object *fixup_data(object *old)
{
std::map<object *,object *>::const_iterator iter = become_map->find(old);
if(iter != become_map->end())
@ -99,9 +99,9 @@ struct slot_become_visitor {
};
struct object_become_visitor {
slot_visitor<slot_become_visitor> *workhorse;
slot_visitor<slot_become_fixup> *workhorse;
explicit object_become_visitor(slot_visitor<slot_become_visitor> *workhorse_) :
explicit object_become_visitor(slot_visitor<slot_become_fixup> *workhorse_) :
workhorse(workhorse_) {}
void operator()(object *obj)
@ -111,9 +111,9 @@ struct object_become_visitor {
};
struct code_block_become_visitor {
slot_visitor<slot_become_visitor> *workhorse;
slot_visitor<slot_become_fixup> *workhorse;
explicit code_block_become_visitor(slot_visitor<slot_become_visitor> *workhorse_) :
explicit code_block_become_visitor(slot_visitor<slot_become_fixup> *workhorse_) :
workhorse(workhorse_) {}
void operator()(code_block *compiled, cell size)
@ -160,7 +160,7 @@ void factor_vm::primitive_become()
/* Update all references to old objects to point to new objects */
{
slot_visitor<slot_become_visitor> workhorse(this,slot_become_visitor(&become_map));
slot_visitor<slot_become_fixup> workhorse(this,slot_become_fixup(&become_map));
workhorse.visit_roots();
workhorse.visit_contexts();

View File

@ -1,6 +1,100 @@
namespace factor
{
/* Size of the object pointed to by an untagged pointer */
template<typename Fixup>
cell object::size(Fixup fixup) const
{
if(free_p()) return ((free_heap_block *)this)->size();
switch(type())
{
case ARRAY_TYPE:
return align(array_size((array*)this),data_alignment);
case BIGNUM_TYPE:
return align(array_size((bignum*)this),data_alignment);
case BYTE_ARRAY_TYPE:
return align(array_size((byte_array*)this),data_alignment);
case STRING_TYPE:
return align(string_size(string_capacity((string*)this)),data_alignment);
case TUPLE_TYPE:
{
tuple_layout *layout = (tuple_layout *)fixup.translate_data(untag<object>(((tuple *)this)->layout));
return align(tuple_size(layout),data_alignment);
}
case QUOTATION_TYPE:
return align(sizeof(quotation),data_alignment);
case WORD_TYPE:
return align(sizeof(word),data_alignment);
case FLOAT_TYPE:
return align(sizeof(boxed_float),data_alignment);
case DLL_TYPE:
return align(sizeof(dll),data_alignment);
case ALIEN_TYPE:
return align(sizeof(alien),data_alignment);
case WRAPPER_TYPE:
return align(sizeof(wrapper),data_alignment);
case CALLSTACK_TYPE:
return align(callstack_object_size(untag_fixnum(((callstack *)this)->length)),data_alignment);
default:
critical_error("Invalid header in size",(cell)this);
return 0; /* can't happen */
}
}
inline cell object::size() const
{
return size(no_fixup());
}
/* The number of cells from the start of the object which should be scanned by
the GC. Some types have a binary payload at the end (string, word, DLL) which
we ignore. */
template<typename Fixup>
cell object::binary_payload_start(Fixup fixup) const
{
if(free_p()) return 0;
switch(type())
{
/* these objects do not refer to other objects at all */
case FLOAT_TYPE:
case BYTE_ARRAY_TYPE:
case BIGNUM_TYPE:
case CALLSTACK_TYPE:
return 0;
/* these objects have some binary data at the end */
case WORD_TYPE:
return sizeof(word) - sizeof(cell) * 3;
case ALIEN_TYPE:
return sizeof(cell) * 3;
case DLL_TYPE:
return sizeof(cell) * 2;
case QUOTATION_TYPE:
return sizeof(quotation) - sizeof(cell) * 2;
case STRING_TYPE:
return sizeof(string);
/* everything else consists entirely of pointers */
case ARRAY_TYPE:
return array_size<array>(array_capacity((array*)this));
case TUPLE_TYPE:
{
tuple_layout *layout = (tuple_layout *)fixup.translate_data(untag<object>(((tuple *)this)->layout));
return tuple_size(layout);
}
case WRAPPER_TYPE:
return sizeof(wrapper);
default:
critical_error("Invalid header in binary_payload_start",(cell)this);
return 0; /* can't happen */
}
}
inline cell object::binary_payload_start() const
{
return binary_payload_start(no_fixup());
}
/* Slot visitors iterate over the slots of an object, applying a functor to
each one that is a non-immediate slot. The pointer is untagged first. The
functor returns a new untagged object pointer. The return value may or may not equal the old one,
@ -17,12 +111,12 @@ Iteration is driven by visit_*() methods. Some of them define GC roots:
- visit_roots()
- visit_contexts() */
template<typename Visitor> struct slot_visitor {
template<typename Fixup> struct slot_visitor {
factor_vm *parent;
Visitor visitor;
Fixup fixup;
explicit slot_visitor<Visitor>(factor_vm *parent_, Visitor visitor_) :
parent(parent_), visitor(visitor_) {}
explicit slot_visitor<Fixup>(factor_vm *parent_, Fixup fixup_) :
parent(parent_), fixup(fixup_) {}
cell visit_pointer(cell pointer);
void visit_handle(cell *handle);
@ -35,35 +129,36 @@ template<typename Visitor> struct slot_visitor {
void visit_callback_roots();
void visit_literal_table_roots();
void visit_roots();
void visit_callstack_object(callstack *stack);
void visit_callstack(context *ctx);
void visit_contexts();
void visit_code_block_objects(code_block *compiled);
void visit_embedded_literals(code_block *compiled);
};
template<typename Visitor>
cell slot_visitor<Visitor>::visit_pointer(cell pointer)
template<typename Fixup>
cell slot_visitor<Fixup>::visit_pointer(cell pointer)
{
if(immediate_p(pointer)) return pointer;
object *untagged = untag<object>(pointer);
untagged = visitor(untagged);
object *untagged = fixup.fixup_data(untag<object>(pointer));
return RETAG(untagged,TAG(pointer));
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_handle(cell *handle)
template<typename Fixup>
void slot_visitor<Fixup>::visit_handle(cell *handle)
{
*handle = visit_pointer(*handle);
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_object_array(cell *start, cell *end)
template<typename Fixup>
void slot_visitor<Fixup>::visit_object_array(cell *start, cell *end)
{
while(start < end) visit_handle(start++);
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_slots(object *ptr, cell payload_start)
template<typename Fixup>
void slot_visitor<Fixup>::visit_slots(object *ptr, cell payload_start)
{
cell *slot = (cell *)ptr;
cell *end = (cell *)((cell)ptr + payload_start);
@ -75,20 +170,23 @@ void slot_visitor<Visitor>::visit_slots(object *ptr, cell payload_start)
}
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_slots(object *ptr)
template<typename Fixup>
void slot_visitor<Fixup>::visit_slots(object *obj)
{
visit_slots(ptr,ptr->binary_payload_start());
if(obj->type() == CALLSTACK_TYPE)
visit_callstack_object((callstack *)obj);
else
visit_slots(obj,obj->binary_payload_start(fixup));
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_stack_elements(segment *region, cell *top)
template<typename Fixup>
void slot_visitor<Fixup>::visit_stack_elements(segment *region, cell *top)
{
visit_object_array((cell *)region->start,top + 1);
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_data_roots()
template<typename Fixup>
void slot_visitor<Fixup>::visit_data_roots()
{
std::vector<data_root_range>::const_iterator iter = parent->data_roots.begin();
std::vector<data_root_range>::const_iterator end = parent->data_roots.end();
@ -97,8 +195,8 @@ void slot_visitor<Visitor>::visit_data_roots()
visit_object_array(iter->start,iter->start + iter->len);
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_bignum_roots()
template<typename Fixup>
void slot_visitor<Fixup>::visit_bignum_roots()
{
std::vector<cell>::const_iterator iter = parent->bignum_roots.begin();
std::vector<cell>::const_iterator end = parent->bignum_roots.end();
@ -108,16 +206,16 @@ void slot_visitor<Visitor>::visit_bignum_roots()
cell *handle = (cell *)(*iter);
if(*handle)
*handle = (cell)visitor(*(object **)handle);
*handle = (cell)fixup.fixup_data(*(object **)handle);
}
}
template<typename Visitor>
template<typename Fixup>
struct callback_slot_visitor {
callback_heap *callbacks;
slot_visitor<Visitor> *visitor;
slot_visitor<Fixup> *visitor;
explicit callback_slot_visitor(callback_heap *callbacks_, slot_visitor<Visitor> *visitor_) :
explicit callback_slot_visitor(callback_heap *callbacks_, slot_visitor<Fixup> *visitor_) :
callbacks(callbacks_), visitor(visitor_) {}
void operator()(code_block *stub)
@ -126,15 +224,15 @@ struct callback_slot_visitor {
}
};
template<typename Visitor>
void slot_visitor<Visitor>::visit_callback_roots()
template<typename Fixup>
void slot_visitor<Fixup>::visit_callback_roots()
{
callback_slot_visitor<Visitor> callback_visitor(parent->callbacks,this);
callback_slot_visitor<Fixup> callback_visitor(parent->callbacks,this);
parent->callbacks->each_callback(callback_visitor);
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_literal_table_roots()
template<typename Fixup>
void slot_visitor<Fixup>::visit_literal_table_roots()
{
std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks;
std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin();
@ -151,8 +249,8 @@ void slot_visitor<Visitor>::visit_literal_table_roots()
parent->code->uninitialized_blocks = new_uninitialized_blocks;
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_roots()
template<typename Fixup>
void slot_visitor<Fixup>::visit_roots()
{
visit_handle(&parent->true_object);
visit_handle(&parent->bignum_zero);
@ -167,8 +265,62 @@ void slot_visitor<Visitor>::visit_roots()
visit_object_array(parent->special_objects,parent->special_objects + special_object_count);
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_contexts()
template<typename Fixup>
struct call_frame_slot_visitor {
factor_vm *parent;
slot_visitor<Fixup> *visitor;
explicit call_frame_slot_visitor(factor_vm *parent_, slot_visitor<Fixup> *visitor_) :
parent(parent_), visitor(visitor_) {}
/*
next -> [entry_point]
[size]
[return address] -- x86 only, backend adds 1 to each spill location
[spill area]
...
frame -> [entry_point]
[size]
*/
void operator()(stack_frame *frame)
{
const code_block *compiled = visitor->fixup.translate_code(parent->frame_code(frame));
gc_info *info = compiled->block_gc_info();
cell return_address = parent->frame_offset(frame);
assert(return_address < compiled->size());
int index = info->return_address_index(return_address);
if(index != -1)
{
u8 *bitmap = info->gc_info_bitmap();
cell base = info->spill_slot_base(index);
cell *stack_pointer = (cell *)(parent->frame_successor(frame) + 1);
for(cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++)
{
if(bitmap_p(bitmap,base + spill_slot))
visitor->visit_handle(&stack_pointer[spill_slot]);
}
}
}
};
template<typename Fixup>
void slot_visitor<Fixup>::visit_callstack_object(callstack *stack)
{
call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
parent->iterate_callstack_object(stack,call_frame_visitor);
}
template<typename Fixup>
void slot_visitor<Fixup>::visit_callstack(context *ctx)
{
call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
parent->iterate_callstack(ctx,call_frame_visitor);
}
template<typename Fixup>
void slot_visitor<Fixup>::visit_contexts()
{
std::set<context *>::const_iterator begin = parent->active_contexts.begin();
std::set<context *>::const_iterator end = parent->active_contexts.end();
@ -179,16 +331,16 @@ void slot_visitor<Visitor>::visit_contexts()
visit_stack_elements(ctx->datastack_seg,(cell *)ctx->datastack);
visit_stack_elements(ctx->retainstack_seg,(cell *)ctx->retainstack);
visit_object_array(ctx->context_objects,ctx->context_objects + context_object_count);
visit_callstack(ctx);
begin++;
}
}
template<typename Visitor>
template<typename Fixup>
struct literal_references_visitor {
slot_visitor<Visitor> *visitor;
slot_visitor<Fixup> *visitor;
explicit literal_references_visitor(slot_visitor<Visitor> *visitor_) : visitor(visitor_) {}
explicit literal_references_visitor(slot_visitor<Fixup> *visitor_) : visitor(visitor_) {}
void operator()(instruction_operand op)
{
@ -197,20 +349,20 @@ struct literal_references_visitor {
}
};
template<typename Visitor>
void slot_visitor<Visitor>::visit_code_block_objects(code_block *compiled)
template<typename Fixup>
void slot_visitor<Fixup>::visit_code_block_objects(code_block *compiled)
{
visit_handle(&compiled->owner);
visit_handle(&compiled->parameters);
visit_handle(&compiled->relocation);
}
template<typename Visitor>
void slot_visitor<Visitor>::visit_embedded_literals(code_block *compiled)
template<typename Fixup>
void slot_visitor<Fixup>::visit_embedded_literals(code_block *compiled)
{
if(!parent->code->uninitialized_p(compiled))
{
literal_references_visitor<Visitor> visitor(this);
literal_references_visitor<Fixup> visitor(this);
compiled->each_instruction_operand(visitor);
}
}

View File

@ -317,10 +317,11 @@ struct factor_vm
void collect_compact(bool trace_contexts_p);
void collect_growing_heap(cell requested_bytes, bool trace_contexts_p);
void gc(gc_op op, cell requested_bytes, bool trace_contexts_p);
void scrub_context(context *ctx);
void scrub_contexts();
void primitive_minor_gc();
void primitive_full_gc();
void primitive_compact_gc();
void inline_gc(cell gc_roots);
void primitive_enable_gc_events();
void primitive_disable_gc_events();
object *allot_object(cell type, cell size);
@ -595,6 +596,7 @@ struct factor_vm
cell frame_executing_quot(stack_frame *frame);
stack_frame *frame_successor(stack_frame *frame);
cell frame_scan(stack_frame *frame);
cell frame_offset(stack_frame *frame);
void primitive_callstack_to_array();
stack_frame *innermost_stack_frame(callstack *stack);
void primitive_innermost_stack_frame_executing();