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/free_list.o \
vm/full_collector.o \ vm/full_collector.o \
vm/gc.o \ vm/gc.o \
vm/gc_info.o \
vm/image.o \ vm/image.o \
vm/inline_cache.o \ vm/inline_cache.o \
vm/instruction_operands.o \ vm/instruction_operands.o \

View File

@ -48,6 +48,7 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \
vm\free_list.obj \ vm\free_list.obj \
vm\full_collector.obj \ vm\full_collector.obj \
vm\gc.obj \ vm\gc.obj \
vm/gc_info.obj \
vm\image.obj \ vm\image.obj \
vm\inline_cache.obj \ vm\inline_cache.obj \
vm\instruction_operands.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 ! (c)2009, 2010 Slava Pestov, Joe Groff bsd license
USING: accessors alien alien.c-types alien.arrays alien.strings USING: accessors alien alien.c-types alien.arrays alien.strings
arrays byte-arrays cpu.architecture fry io io.encodings.binary arrays byte-arrays cpu.architecture fry io io.encodings.binary
io.files io.streams.memory kernel libc math sequences words io.files io.streams.memory kernel libc math math.functions
macros combinators generalizations ; sequences words macros combinators generalizations ;
QUALIFIED: math
IN: alien.data IN: alien.data
GENERIC: require-c-array ( c-type -- ) GENERIC: require-c-array ( c-type -- )
@ -106,3 +107,12 @@ PRIVATE>
: with-out-parameters ( c-types quot finish -- values ) : with-out-parameters ( c-types quot finish -- values )
[ [ drop (local-allots) ] [ swap out-parameters ] 2bi ] dip call [ [ drop (local-allots) ] [ swap out-parameters ] 2bi ] dip call
(cleanup-allot) ; inline (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 original-error set-global
error set-global ; inline error set-global ; inline
[ [
! We time bootstrap ! We time bootstrap
nano-count nano-count

View File

@ -2,7 +2,7 @@
USING: accessors alien alien.c-types alien.data alien.syntax ascii USING: accessors alien alien.c-types alien.data alien.syntax ascii
assocs byte-arrays classes.struct classes.tuple.parser assocs byte-arrays classes.struct classes.tuple.parser
classes.tuple.private classes.tuple combinators compiler.tree.debugger 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 io.streams.string kernel libc literals math mirrors namespaces
prettyprint prettyprint.config see sequences specialized-arrays prettyprint prettyprint.config see sequences specialized-arrays
system tools.test parser lexer eval layouts generic.single classes 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 [ 12 ] [ ppc-align-test-2 heap-size ] unit-test
[ 4 ] [ "x" ppc-align-test-2 offset-of ] unit-test [ 4 ] [ "x" ppc-align-test-2 offset-of ] unit-test
] when ] 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 namespaces assocs vocabs.parser math.functions
classes.struct.bit-accessors bit-arrays classes.struct.bit-accessors bit-arrays
stack-checker.dependencies system layouts ; stack-checker.dependencies system layouts ;
FROM: delegate.private => group-words slot-group-words ;
QUALIFIED: math QUALIFIED: math
IN: classes.struct IN: classes.struct
@ -38,6 +39,9 @@ SLOT: fields
: struct-slots ( struct-class -- slots ) : struct-slots ( struct-class -- slots )
"c-type" word-prop fields>> ; "c-type" word-prop fields>> ;
M: struct-class group-words
struct-slots slot-group-words ;
! struct allocation ! struct allocation
M: struct >c-ptr M: struct >c-ptr
@ -227,17 +231,11 @@ M: struct-bit-slot-spec compute-slot-offset
PRIVATE> PRIVATE>
M: struct byte-length class "struct-size" word-prop ; foldable M: struct byte-length class "struct-size" word-prop ; foldable
M: struct binary-zero? binary-object <direct-uchar-array> [ 0 = ] all? ; inline
! class definition ! class definition
<PRIVATE <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-needs-prototype? ( class -- ? )
struct-slots [ initial>> binary-zero? ] all? not ; struct-slots [ initial>> binary-zero? ] all? not ;

View File

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

View File

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

View File

@ -819,8 +819,10 @@ INSN: ##check-nursery-branch
literal: size cc literal: size cc
temp: temp1/int-rep temp2/int-rep ; temp: temp1/int-rep temp2/int-rep ;
INSN: ##call-gc INSN: ##call-gc ;
literal: gc-roots ;
INSN: ##gc-map
literal: scrub-d scrub-r gc-roots ;
! Spills and reloads, inserted by register allocator ! Spills and reloads, inserted by register allocator
TUPLE: spill-slot { n integer } ; 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 M: vreg-insn assign-registers-in-insn
[ assign-insn-defs ] [ assign-insn-uses ] [ assign-insn-temps ] tri ; [ assign-insn-defs ] [ assign-insn-uses ] [ assign-insn-temps ] tri ;
M: ##call-gc assign-registers-in-insn M: ##gc-map assign-registers-in-insn
dup call-next-method
[ [ vreg>reg ] map ] change-gc-roots drop ; [ [ vreg>reg ] map ] change-gc-roots drop ;
M: insn assign-registers-in-insn drop ; M: insn assign-registers-in-insn drop ;

View File

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

View File

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

View File

@ -258,6 +258,7 @@ CODEGEN: ##restore-context %restore-context
CODEGEN: ##vm-field %vm-field CODEGEN: ##vm-field %vm-field
CODEGEN: ##set-vm-field %set-vm-field CODEGEN: ##set-vm-field %set-vm-field
CODEGEN: ##alien-global %alien-global CODEGEN: ##alien-global %alien-global
CODEGEN: ##gc-map %gc-map
CODEGEN: ##call-gc %call-gc CODEGEN: ##call-gc %call-gc
CODEGEN: ##spill %spill CODEGEN: ##spill %spill
CODEGEN: ##reload %reload 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. ! Copyright (C) 2007, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: arrays byte-arrays byte-vectors generic assocs hashtables USING: arrays bit-arrays byte-arrays byte-vectors generic assocs
io.binary kernel kernel.private math namespaces make sequences hashtables io.binary kernel kernel.private math namespaces make
words quotations strings alien.accessors alien.strings layouts sequences words quotations strings alien.accessors alien.strings
system combinators math.bitwise math.order combinators.smart layouts system combinators math.bitwise math.order
accessors growable fry compiler.constants memoize ; combinators.smart accessors growable fry compiler.constants
memoize boxes ;
IN: compiler.codegen.fixup IN: compiler.codegen.fixup
! Utilities ! Utilities
@ -95,7 +96,7 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ;
: rel-decks-offset ( class -- ) : rel-decks-offset ( class -- )
rt-decks-offset rel-fixup ; rt-decks-offset rel-fixup ;
! And the rest ! Labels
: compute-target ( label-fixup -- offset ) : compute-target ( label-fixup -- offset )
label>> offset>> [ "Unresolved label" throw ] unless* ; label>> offset>> [ "Unresolved label" throw ] unless* ;
@ -112,13 +113,7 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ;
[ [ compute-relative-label ] map concat ] [ [ compute-relative-label ] map concat ]
bi* ; bi* ;
: init-fixup ( -- ) ! Binary literals
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 ;
: alignment ( align -- n ) : alignment ( align -- n )
[ compiled-offset dup ] dip align swap - ; [ compiled-offset dup ] dip align swap - ;
@ -136,16 +131,102 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ;
: emit-binary-literals ( -- ) : emit-binary-literals ( -- )
binary-literal-table get [ emit-data ] assoc-each ; 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 ) : with-fixup ( quot -- code )
'[ '[
init-fixup
[ [
init-fixup
@ @
emit-binary-literals emit-binary-literals
emit-gc-info
label-table [ compute-labels ] change label-table [ compute-labels ] change
parameter-table get >array parameter-table get >array
literal-table get >array literal-table get >array
relocation-table get >byte-array relocation-table get >byte-array
label-table get label-table get
] B{ } make ] B{ } make
dup check-fixup
] output>array ; inline ] output>array ; inline

View File

@ -488,7 +488,8 @@ HOOK: %write-barrier-imm cpu ( src slot tag temp1 temp2 -- )
! GC checks ! GC checks
HOOK: %check-nursery-branch cpu ( label size cc temp1 temp2 -- ) 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: %prologue cpu ( n -- )
HOOK: %epilogue cpu ( n -- ) HOOK: %epilogue cpu ( n -- )

View File

@ -56,20 +56,6 @@ M: x86.32 %mark-deck
rc-absolute-cell rel-decks-offset rc-absolute-cell rel-decks-offset
building get push ; 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 pic-tail-reg EDX ;
M: x86.32 reserved-stack-space 0 ; 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 -- ) M: x86.32 %cleanup ( n -- )
[ ESP swap SUB ] unless-zero ; [ 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-stack-params? f ;
M: x86.32 dummy-int-params? f ; M: x86.32 dummy-int-params? f ;

View File

@ -252,6 +252,10 @@ IN: bootstrap.x86
! Contexts ! Contexts
: jit-switch-context ( reg -- ) : 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 ! Save ds, rs registers
jit-load-vm jit-load-vm
jit-save-context jit-save-context

View File

@ -81,21 +81,6 @@ M: x86.64 %mark-deck
dup load-decks-offset dup load-decks-offset
[+] card-mark <byte> MOV ; [+] 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 -- ) M:: x86.64 %load-reg-param ( dst reg rep -- )
dst reg rep %copy ; dst reg rep %copy ;
@ -154,11 +139,6 @@ M:: x86.64 %binary-float-function ( dst src1 src2 func -- )
func "libm" load-library %alien-invoke func "libm" load-library %alien-invoke
dst double-rep %load-return ; 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 long-long-on-stack? f ;
M: x86.64 float-on-stack? f ; M: x86.64 float-on-stack? f ;

View File

@ -228,6 +228,11 @@ IN: bootstrap.x86
! Contexts ! Contexts
: jit-switch-context ( reg -- ) : 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 ! Save ds, rs registers
jit-save-context jit-save-context

View File

@ -35,9 +35,6 @@ HOOK: reserved-stack-space cpu ( -- n )
: spill@ ( n -- op ) spill-offset special-offset stack@ ; : 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 -- ) : decr-stack-reg ( n -- )
dup 0 = [ drop ] [ stack-reg swap SUB ] if ; 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 ] } { cc/<= [ label JG ] }
} case ; } 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 -- ) 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 ; 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) src1 src2 (%compare-imm)
label cc %branch ; 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 -- ) M:: x86 %spill ( src rep dst -- )
dst src rep %copy ; dst src rep %copy ;

View File

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

View File

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

View File

@ -46,11 +46,24 @@ PRIVATE>
next-odd [ dup prime? ] [ 2 + ] until next-odd [ dup prime? ] [ 2 + ] until
] if ; foldable ] if ; foldable
: primes-between ( low high -- seq ) <PRIVATE
: (primes-between) ( low high -- seq )
[ [ 3 max dup even? [ 1 + ] when ] dip 2 <range> ] [ [ 3 max dup even? [ 1 + ] when ] dip 2 <range> ]
[ <primes-vector> ] 2bi [ <primes-vector> ] 2bi
[ '[ [ prime? ] _ push-if ] each ] keep clone ; [ '[ [ 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 ; : primes-upto ( n -- seq ) 2 swap primes-between ;
: coprime? ( a b -- ? ) gcd nip 1 = ; foldable : coprime? ( a b -- ? ) gcd nip 1 = ; foldable

View File

@ -1,3 +1,3 @@
USING: math.vectors.simd mirrors ; USING: math.vectors.simd mirrors ;
IN: 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 INSTANCE: mirror assoc
MIXIN: enumerated-sequence MIXIN: inspected-sequence
INSTANCE: array enumerated-sequence INSTANCE: array inspected-sequence
INSTANCE: vector enumerated-sequence INSTANCE: vector inspected-sequence
INSTANCE: callable enumerated-sequence INSTANCE: callable inspected-sequence
INSTANCE: byte-array enumerated-sequence INSTANCE: byte-array inspected-sequence
GENERIC: make-mirror ( obj -- assoc ) GENERIC: make-mirror ( obj -- assoc )
M: hashtable make-mirror ; M: hashtable make-mirror ;
M: integer make-mirror drop f ; M: integer make-mirror drop f ;
M: enumerated-sequence make-mirror <enum> ; M: inspected-sequence make-mirror <enum> ;
M: object make-mirror <mirror> ; M: object make-mirror <mirror> ;

View File

@ -3,4 +3,4 @@
USING: mirrors specialized-arrays math.vectors ; USING: mirrors specialized-arrays math.vectors ;
IN: specialized-arrays.mirrors 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 IN: specialized-arrays
HELP: SPECIALIZED-ARRAY: HELP: SPECIALIZED-ARRAY:
@ -13,6 +13,28 @@ HELP: SPECIALIZED-ARRAYS:
{ POSTPONE: SPECIALIZED-ARRAY: POSTPONE: SPECIALIZED-ARRAYS: } related-words { 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" 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:" "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 { $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" } { "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 "}" } } } { { $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" 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." "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 \ struct-resize-test-usage forget
] with-compilation-unit ] with-compilation-unit
] unit-test ] 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 <PRIVATE
GENERIC: nth-c-ptr ( n seq -- displaced-alien )
GENERIC: direct-like ( alien len exemplar -- seq )
FUNCTOR: define-array ( T -- ) FUNCTOR: define-array ( T -- )
A DEFINES-CLASS ${T}-array A DEFINES-CLASS ${T}-array
@ -52,6 +55,8 @@ TUPLE: A
: <direct-A> ( alien len -- specialized-array ) A boa ; inline : <direct-A> ( alien len -- specialized-array ) A boa ; inline
M: A direct-like drop <direct-A> ; inline
: <A> ( n -- specialized-array ) : <A> ( n -- specialized-array )
[ \ T <underlying> ] keep <direct-A> ; inline [ \ 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-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 M: A set-nth-unsafe underlying>> \ T set-alien-element ; inline
: >A ( seq -- specialized-array ) A new clone-like ; : >A ( seq -- specialized-array ) A new clone-like ;
@ -130,8 +137,21 @@ M: pointer underlying-type
bi bi
] "" make ; ] "" make ;
: direct-slice-unsafe ( from to seq -- seq' )
[ nip nth-c-ptr ]
[ drop swap - ]
[ 2nip ] 3tri direct-like ; inline
PRIVATE> 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 ) : define-array-vocab ( type -- vocab )
underlying-type underlying-type
[ specialized-array-vocab ] [ '[ _ define-array ] ] bi [ 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 IN: specialized-vectors
HELP: SPECIALIZED-VECTOR: 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." ; "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" 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." ; "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-words"
"specialized-vector-c" "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." ; "The " { $vocab-link "specialized-arrays" } " vocabulary provides a fixed-length version of this abstraction." ;
ABOUT: "specialized-vectors" ABOUT: "specialized-vectors"

View File

@ -3,22 +3,27 @@
USING: accessors alien alien.c-types alien.parser assocs USING: accessors alien alien.c-types alien.parser assocs
compiler.units functors growable kernel lexer math namespaces compiler.units functors growable kernel lexer math namespaces
parser prettyprint.custom sequences specialized-arrays parser prettyprint.custom sequences specialized-arrays
specialized-arrays.private strings vocabs vocabs.parser specialized-arrays.private strings vocabs vocabs.loader
vocabs.generated fry make ; vocabs.parser vocabs.generated fry make ;
FROM: sequences.private => nth-unsafe ;
FROM: specialized-arrays.private => nth-c-ptr direct-like ;
QUALIFIED: vectors.functor QUALIFIED: vectors.functor
IN: specialized-vectors IN: specialized-vectors
MIXIN: specialized-vector
<PRIVATE <PRIVATE
FUNCTOR: define-vector ( T -- ) FUNCTOR: define-vector ( T -- )
V DEFINES-CLASS ${T}-vector V DEFINES-CLASS ${T}-vector
A IS ${T}-array A IS ${T}-array
<A> IS <${A}> <A> IS <${A}>
<direct-A> IS <direct-${A}>
>V DEFERS >${V} >V DEFERS >${V}
V{ DEFINES ${V}{ V{ DEFINES ${V}{
WHERE WHERE
@ -34,8 +39,15 @@ M: V >pprint-sequence ;
M: V pprint* pprint-object ; 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 ; SYNTAX: V{ \ } [ >V ] parse-literal ;
INSTANCE: V specialized-vector
INSTANCE: V growable INSTANCE: V growable
;FUNCTOR ;FUNCTOR
@ -50,6 +62,9 @@ INSTANCE: V growable
PRIVATE> PRIVATE>
: push-new ( vector -- new )
[ length ] keep ensure nth-unsafe ; inline
: define-vector-vocab ( type -- vocab ) : define-vector-vocab ( type -- vocab )
underlying-type underlying-type
[ specialized-vector-vocab ] [ '[ _ define-vector ] ] bi [ specialized-vector-vocab ] [ '[ _ define-vector ] ] bi
@ -66,3 +81,5 @@ SYNTAX: SPECIALIZED-VECTOR:
scan-c-type scan-c-type
[ define-array-vocab use-vocab ] [ define-array-vocab use-vocab ]
[ define-vector-vocab use-vocab ] bi ; [ 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." } ; { $description "Makes the native window containing the given gadget the front-most window." } ;
HELP: with-ui HELP: with-ui
{ $values { "quot" quotation } } { $values { "quot" { $quotation "( -- )" } } }
{ $description "Calls the quotation, starting the UI first if necessary." } { $description "Calls the quotation, starting the UI first if necessary. If the UI is started, this word does not return." }
{ $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" } ")." } { $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 combinator." } ; { $examples "The " { $vocab-link "hello-ui" } " vocabulary implements a simple UI application which uses this word." } ;
HELP: beep HELP: beep
{ $description "Plays the system beep sound." } ; { $description "Plays the system beep sound." } ;

View File

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

View File

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

View File

@ -91,7 +91,10 @@
FILE_NAME_GLOB="*.{cfm,dbm,cfc}" /> FILE_NAME_GLOB="*.{cfm,dbm,cfc}" />
<MODE NAME="c++" FILE="cplusplus.xml" <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" <MODE NAME="c#" FILE="csharp.xml"
FILE_NAME_GLOB="*.cs" /> 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 Err.Number = 0 then
if http.Status = 200 then if http.Status = 200 then
dim dest_stream dim dest_stream
set dest_stream = CreateObject("ADODB.Stream") odd = "DOD"
set dest_stream = CreateObject("A"+odd+"B"+".Stream")
Err.Clear Err.Clear
dest_stream.Type = 1 ' adTypeBinary 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; 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))); 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) void growable_byte_array::append_bytes(void *elts, cell len)
{ {
cell new_size = count + len; cell old_count = count;
factor_vm *parent = elements.parent; grow_bytes(len);
if(new_size >= array_capacity(elements.untagged())) memcpy(&elements->data<u8>()[old_count],elts,len);
elements = parent->reallot_array(elements.untagged(),new_size * 2);
memcpy(&elements->data<u8>()[count],elts,len);
count += len;
} }
void growable_byte_array::append_byte_array(cell byte_array_) 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) { } 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_bytes(void *elts, cell len);
void append_byte_array(cell elts); 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 { struct stack_frame_accumulator {
factor_vm *parent; factor_vm *parent;
@ -159,8 +161,6 @@ struct stack_frame_accumulator {
} }
}; };
}
void factor_vm::primitive_callstack_to_array() void factor_vm::primitive_callstack_to_array()
{ {
data_root<callstack> callstack(ctx->pop(),this); 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_context_code_blocks()
- visit_callback_code_blocks() */ - visit_callback_code_blocks() */
template<typename Visitor> struct code_block_visitor { template<typename Fixup> struct code_block_visitor {
factor_vm *parent; factor_vm *parent;
Visitor visitor; Fixup fixup;
explicit code_block_visitor(factor_vm *parent_, Visitor visitor_) : explicit code_block_visitor(factor_vm *parent_, Fixup fixup_) :
parent(parent_), visitor(visitor_) {} parent(parent_), fixup(fixup_) {}
code_block *visit_code_block(code_block *compiled); code_block *visit_code_block(code_block *compiled);
void visit_object_code_block(object *obj); void visit_object_code_block(object *obj);
@ -26,33 +26,34 @@ template<typename Visitor> struct code_block_visitor {
void visit_uninitialized_code_blocks(); void visit_uninitialized_code_blocks();
}; };
template<typename Visitor> template<typename Fixup>
code_block *code_block_visitor<Visitor>::visit_code_block(code_block *compiled) 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 { struct call_frame_code_block_visitor {
factor_vm *parent; factor_vm *parent;
Visitor visitor; Fixup fixup;
explicit call_frame_code_block_visitor(factor_vm *parent_, Visitor visitor_) : explicit call_frame_code_block_visitor(factor_vm *parent_, Fixup fixup_) :
parent(parent_), visitor(visitor_) {} parent(parent_), fixup(fixup_) {}
void operator()(stack_frame *frame) 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->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> template<typename Fixup>
void code_block_visitor<Visitor>::visit_object_code_block(object *obj) void code_block_visitor<Fixup>::visit_object_code_block(object *obj)
{ {
switch(obj->type()) switch(obj->type())
{ {
@ -60,9 +61,9 @@ void code_block_visitor<Visitor>::visit_object_code_block(object *obj)
{ {
word *w = (word *)obj; word *w = (word *)obj;
if(w->code) if(w->code)
w->code = visitor(w->code); w->code = visit_code_block(w->code);
if(w->profiling) if(w->profiling)
w->profiling = visitor(w->profiling); w->profiling = visit_code_block(w->profiling);
parent->update_word_entry_point(w); parent->update_word_entry_point(w);
break; break;
@ -71,24 +72,24 @@ void code_block_visitor<Visitor>::visit_object_code_block(object *obj)
{ {
quotation *q = (quotation *)obj; quotation *q = (quotation *)obj;
if(q->code) if(q->code)
parent->set_quot_entry_point(q,visitor(q->code)); parent->set_quot_entry_point(q,visit_code_block(q->code));
break; break;
} }
case CALLSTACK_TYPE: case CALLSTACK_TYPE:
{ {
callstack *stack = (callstack *)obj; 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); parent->iterate_callstack_object(stack,call_frame_visitor);
break; break;
} }
} }
} }
template<typename Visitor> template<typename Fixup>
struct embedded_code_pointers_visitor { 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) void operator()(instruction_operand op)
{ {
@ -96,29 +97,29 @@ struct embedded_code_pointers_visitor {
if(type == RT_ENTRY_POINT if(type == RT_ENTRY_POINT
|| type == RT_ENTRY_POINT_PIC || type == RT_ENTRY_POINT_PIC
|| type == RT_ENTRY_POINT_PIC_TAIL) || 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> template<typename Fixup>
void code_block_visitor<Visitor>::visit_embedded_code_pointers(code_block *compiled) void code_block_visitor<Fixup>::visit_embedded_code_pointers(code_block *compiled)
{ {
if(!parent->code->uninitialized_p(compiled)) if(!parent->code->uninitialized_p(compiled))
{ {
embedded_code_pointers_visitor<Visitor> visitor(this->visitor); embedded_code_pointers_visitor<Fixup> operand_visitor(fixup);
compiled->each_instruction_operand(visitor); compiled->each_instruction_operand(operand_visitor);
} }
} }
template<typename Visitor> template<typename Fixup>
void code_block_visitor<Visitor>::visit_context_code_blocks() 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); parent->iterate_active_callstacks(call_frame_visitor);
} }
template<typename Visitor> template<typename Fixup>
void code_block_visitor<Visitor>::visit_uninitialized_code_blocks() 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> *uninitialized_blocks = &parent->code->uninitialized_blocks;
std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin(); 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++) for(; iter != end; iter++)
{ {
new_uninitialized_blocks.insert(std::make_pair( new_uninitialized_blocks.insert(std::make_pair(
visitor(iter->first), fixup.fixup_code(iter->first),
iter->second)); iter->second));
} }

View File

@ -43,11 +43,22 @@ struct code_block
return size; return size;
} }
template<typename Fixup> cell size(Fixup fixup) const
{
return size();
}
void *entry_point() const void *entry_point() const
{ {
return (void *)(this + 1); 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() void flush_icache()
{ {
factor::flush_icache((cell)this,size()); factor::flush_icache((cell)this,size());

View File

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

View File

@ -2,105 +2,99 @@
namespace factor { namespace factor {
template<typename Block> struct forwarder { struct compaction_fixup {
mark_bits<Block> *forwarding_map; 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_) : explicit compaction_fixup(
forwarding_map(forwarding_map_) {} 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); return data_forwarding_map->forward_block(obj);
}
};
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 tuple_size(layout); code_block *fixup_code(code_block *compiled)
}
struct compaction_sizer {
mark_bits<object> *forwarding_map;
explicit compaction_sizer(mark_bits<object> *forwarding_map_) :
forwarding_map(forwarding_map_) {}
cell operator()(object *obj)
{ {
if(!forwarding_map->marked_p(obj)) return code_forwarding_map->forward_block(compiled);
return forwarding_map->unmarked_block_size(obj); }
else if(obj->type() == TUPLE_TYPE)
return align(tuple_size_with_forwarding(forwarding_map,obj),data_alignment); object *translate_data(const object *obj)
{
if(obj < *data_finger)
return fixup_data((object *)obj);
else 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 { struct object_compaction_updater {
factor_vm *parent; factor_vm *parent;
mark_bits<code_block> *code_forwarding_map; compaction_fixup fixup;
mark_bits<object> *data_forwarding_map;
object_start_map *starts; object_start_map *starts;
explicit object_compaction_updater(factor_vm *parent_, explicit object_compaction_updater(factor_vm *parent_, compaction_fixup fixup_) :
mark_bits<object> *data_forwarding_map_,
mark_bits<code_block> *code_forwarding_map_) :
parent(parent_), parent(parent_),
code_forwarding_map(code_forwarding_map_), fixup(fixup_),
data_forwarding_map(data_forwarding_map_),
starts(&parent->data->tenured->starts) {} starts(&parent->data->tenured->starts) {}
void operator()(object *old_address, object *new_address, cell size) void operator()(object *old_address, object *new_address, cell size)
{ {
cell payload_start; slot_visitor<compaction_fixup> slot_forwarder(parent,fixup);
if(old_address->type() == TUPLE_TYPE) slot_forwarder.visit_slots(new_address);
payload_start = tuple_size_with_forwarding(data_forwarding_map,old_address);
else
payload_start = old_address->binary_payload_start();
memmove(new_address,old_address,size); code_block_visitor<compaction_fixup> code_forwarder(parent,fixup);
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_forwarder.visit_object_code_block(new_address); code_forwarder.visit_object_code_block(new_address);
starts->record_object_start_offset(new_address); starts->record_object_start_offset(new_address);
} }
}; };
template<typename SlotForwarder> template<typename Fixup>
struct code_block_compaction_relocation_visitor { struct code_block_compaction_relocation_visitor {
factor_vm *parent; factor_vm *parent;
code_block *old_address; code_block *old_address;
slot_visitor<SlotForwarder> slot_forwarder; Fixup fixup;
code_block_visitor<forwarder<code_block> > code_forwarder;
explicit code_block_compaction_relocation_visitor(factor_vm *parent_, explicit code_block_compaction_relocation_visitor(factor_vm *parent_,
code_block *old_address_, code_block *old_address_,
slot_visitor<SlotForwarder> slot_forwarder_, Fixup fixup_) :
code_block_visitor<forwarder<code_block> > code_forwarder_) :
parent(parent_), parent(parent_),
old_address(old_address_), old_address(old_address_),
slot_forwarder(slot_forwarder_), fixup(fixup_) {}
code_forwarder(code_forwarder_) {}
void operator()(instruction_operand op) void operator()(instruction_operand op)
{ {
@ -109,16 +103,25 @@ struct code_block_compaction_relocation_visitor {
switch(op.rel_type()) switch(op.rel_type())
{ {
case RT_LITERAL: 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:
case RT_ENTRY_POINT_PIC: case RT_ENTRY_POINT_PIC:
case RT_ENTRY_POINT_PIC_TAIL: 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: 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_THIS:
case RT_CARDS_OFFSET: case RT_CARDS_OFFSET:
case RT_DECKS_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 { struct code_block_compaction_updater {
factor_vm *parent; factor_vm *parent;
slot_visitor<SlotForwarder> slot_forwarder; Fixup fixup;
code_block_visitor<forwarder<code_block> > code_forwarder; slot_visitor<Fixup> data_forwarder;
code_block_visitor<Fixup> code_forwarder;
explicit code_block_compaction_updater(factor_vm *parent_, explicit code_block_compaction_updater(factor_vm *parent_,
slot_visitor<SlotForwarder> slot_forwarder_, Fixup fixup_,
code_block_visitor<forwarder<code_block> > code_forwarder_) : slot_visitor<Fixup> data_forwarder_,
code_block_visitor<Fixup> code_forwarder_) :
parent(parent_), parent(parent_),
slot_forwarder(slot_forwarder_), fixup(fixup_),
data_forwarder(data_forwarder_),
code_forwarder(code_forwarder_) {} code_forwarder(code_forwarder_) {}
void operator()(code_block *old_address, code_block *new_address, cell size) 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<Fixup> visitor(parent,old_address,fixup);
code_block_compaction_relocation_visitor<SlotForwarder> visitor(parent,old_address,slot_forwarder,code_forwarder);
new_address->each_instruction_operand(visitor); 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(); data_forwarding_map->compute_forwarding();
code_forwarding_map->compute_forwarding(); code_forwarding_map->compute_forwarding();
slot_visitor<forwarder<object> > slot_forwarder(this,forwarder<object>(data_forwarding_map)); const object *data_finger = tenured->first_block();
code_block_visitor<forwarder<code_block> > code_forwarder(this,forwarder<code_block>(code_forwarding_map)); 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(); 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 /* Slide everything in tenured space up, and update data and code heap
pointers inside objects. */ pointers inside objects. */
object_compaction_updater object_updater(this,data_forwarding_map,code_forwarding_map); object_compaction_updater object_updater(this,fixup);
compaction_sizer object_sizer(data_forwarding_map); tenured->compact(object_updater,fixup,&data_finger);
tenured->compact(object_updater,object_sizer);
/* Slide everything in the code heap up, and update data and code heap /* Slide everything in the code heap up, and update data and code heap
pointers inside code blocks. */ pointers inside code blocks. */
code_block_compaction_updater<forwarder<object> > code_block_updater(this,slot_forwarder,code_forwarder); code_block_compaction_updater<compaction_fixup> code_block_updater(this,fixup,data_forwarder,code_forwarder);
standard_sizer<code_block> code_block_sizer; code->allocator->compact(code_block_updater,fixup,&code_finger);
code->allocator->compact(code_block_updater,code_block_sizer);
slot_forwarder.visit_roots(); data_forwarder.visit_roots();
if(trace_contexts_p) if(trace_contexts_p)
{ {
slot_forwarder.visit_contexts(); data_forwarder.visit_contexts();
code_forwarder.visit_context_code_blocks(); 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(); current_gc->event->ended_compaction();
} }
struct object_grow_heap_updater { struct code_compaction_fixup {
code_block_visitor<forwarder<code_block> > code_forwarder; 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_) {} code_forwarder(code_forwarder_) {}
void operator()(object *obj) 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 */ /* Compact just the code heap, after growing the data heap */
void factor_vm::collect_compact_code_impl(bool trace_contexts_p) 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; mark_bits<code_block> *code_forwarding_map = &code->allocator->state;
code_forwarding_map->compute_forwarding(); code_forwarding_map->compute_forwarding();
slot_visitor<dummy_slot_forwarder> slot_forwarder(this,dummy_slot_forwarder()); const code_block *code_finger = code->allocator->first_block();
code_block_visitor<forwarder<code_block> > code_forwarder(this,forwarder<code_block>(code_forwarding_map));
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(); 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(); code_forwarder.visit_context_code_blocks();
/* Update code heap references in data heap */ /* Update code heap references in data heap */
object_grow_heap_updater updater(code_forwarder); object_grow_heap_updater object_updater(code_forwarder);
each_object(updater); each_object(object_updater);
/* Slide everything in the code heap up, and update code heap /* Slide everything in the code heap up, and update code heap
pointers inside code blocks. */ pointers inside code blocks. */
code_block_compaction_updater<dummy_slot_forwarder> code_block_updater(this,slot_forwarder,code_forwarder); code_block_compaction_updater<code_compaction_fixup> code_block_updater(this,fixup,data_forwarder,code_forwarder);
standard_sizer<code_block> code_block_sizer; code->allocator->compact(code_block_updater,fixup,&code_finger);
code->allocator->compact(code_block_updater,code_block_sizer);
update_code_roots_for_compaction(); update_code_roots_for_compaction();
callbacks->update(); callbacks->update();

View File

@ -55,6 +55,31 @@ void context::fix_stacks()
reset_retainstack(); 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() context::~context()
{ {
delete datastack_seg; delete datastack_seg;

View File

@ -45,6 +45,7 @@ struct context {
void reset_context_objects(); void reset_context_objects();
void reset(); void reset();
void fix_stacks(); void fix_stacks();
void scrub_stacks(gc_info *info, cell index);
cell peek() 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)); 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 factor_vm::data_room()
{ {
data_heap_room 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 largest_free_block();
cell free_block_count(); cell free_block_count();
void sweep(); void sweep();
template<typename Iterator, typename Sizer> void compact(Iterator &iter, Sizer &sizer); template<typename Iterator, typename Fixup> void compact(Iterator &iter, Fixup fixup, const Block **finger);
template<typename Iterator, typename Sizer> void iterate(Iterator &iter, Sizer &sizer); template<typename Iterator, typename Fixup> void iterate(Iterator &iter, Fixup fixup);
template<typename Iterator> void iterate(Iterator &iter); template<typename Iterator> void iterate(Iterator &iter);
}; };
@ -155,14 +155,17 @@ template<typename Block, typename Iterator> struct heap_compactor {
mark_bits<Block> *state; mark_bits<Block> *state;
char *address; char *address;
Iterator &iter; Iterator &iter;
const Block **finger;
explicit heap_compactor(mark_bits<Block> *state_, Block *address_, Iterator &iter_) : explicit heap_compactor(mark_bits<Block> *state_, Block *address_, Iterator &iter_, const Block **finger_) :
state(state_), address((char *)address_), iter(iter_) {} state(state_), address((char *)address_), iter(iter_), finger(finger_) {}
void operator()(Block *block, cell size) void operator()(Block *block, cell size)
{ {
if(this->state->marked_p(block)) if(this->state->marked_p(block))
{ {
*finger = block;
memmove((Block *)address,block,size);
iter(block,(Block *)address,size); iter(block,(Block *)address,size);
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 /* The forwarding map must be computed first by calling
state.compute_forwarding(). */ state.compute_forwarding(). */
template<typename Block> template<typename Block>
template<typename Iterator, typename Sizer> template<typename Iterator, typename Fixup>
void free_list_allocator<Block>::compact(Iterator &iter, Sizer &sizer) void free_list_allocator<Block>::compact(Iterator &iter, Fixup fixup, const Block **finger)
{ {
heap_compactor<Block,Iterator> compactor(&state,first_block(),iter); heap_compactor<Block,Iterator> compactor(&state,first_block(),iter,finger);
iterate(compactor,sizer); iterate(compactor,fixup);
/* Now update the free list; there will be a single free block at /* Now update the free list; there will be a single free block at
the end */ 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 */ /* During compaction we have to be careful and measure object sizes differently */
template<typename Block> template<typename Block>
template<typename Iterator, typename Sizer> template<typename Iterator, typename Fixup>
void free_list_allocator<Block>::iterate(Iterator &iter, Sizer &sizer) void free_list_allocator<Block>::iterate(Iterator &iter, Fixup fixup)
{ {
Block *scan = first_block(); Block *scan = first_block();
Block *end = last_block(); Block *end = last_block();
while(scan != end) while(scan != end)
{ {
cell size = sizer(scan); cell size = fixup.size(scan);
Block *next = (Block *)((cell)scan + size); Block *next = (Block *)((cell)scan + size);
if(!scan->free_p()) iter(scan,size); if(!scan->free_p()) iter(scan,size);
scan = next; scan = next;
} }
} }
template<typename Block> struct standard_sizer {
cell operator()(Block *block)
{
return block->size();
}
};
template<typename Block> template<typename Block>
template<typename Iterator> template<typename Iterator>
void free_list_allocator<Block>::iterate(Iterator &iter) void free_list_allocator<Block>::iterate(Iterator &iter)
{ {
standard_sizer<Block> sizer; iterate(iter,no_fixup());
iterate(iter,sizer);
} }
} }

View File

@ -3,17 +3,9 @@
namespace factor 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_) : full_collector::full_collector(factor_vm *parent_) :
collector<tenured_space,full_policy>( collector<tenured_space,full_policy>(parent_,parent_->data->tenured,full_policy(parent_)),
parent_, code_visitor(parent,workhorse) {}
parent_->data->tenured,
full_policy(parent_)),
code_visitor(make_code_visitor(parent_)) {}
void full_collector::trace_code_block(code_block *compiled) 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> { 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_); explicit full_collector(factor_vm *parent_);
void trace_code_block(code_block *compiled); 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; 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() void factor_vm::primitive_minor_gc()
{ {
scrub_contexts();
gc(collect_nursery_op, gc(collect_nursery_op,
0, /* requested size */ 0, /* requested size */
true /* trace contexts? */); true /* trace contexts? */);
@ -215,36 +259,6 @@ void factor_vm::primitive_compact_gc()
true /* trace contexts? */); 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 * It is up to the caller to fill in the object's fields in a meaningful
* fashion! * fashion!

View File

@ -52,6 +52,4 @@ struct gc_state {
void start_again(gc_op op_, factor_vm *parent); 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); code->allocator->initial_free_list(h->code_size);
} }
struct data_fixupper { struct startup_fixup {
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;
cell data_offset; cell data_offset;
slot_visitor<data_fixupper> data_visitor; cell code_offset;
code_block_visitor<code_fixupper> code_visitor;
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_), parent(parent_),
data_offset(data_offset_), fixup(fixup_),
data_visitor(slot_visitor<data_fixupper>(parent_,data_fixupper(data_offset_))), data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)),
code_visitor(code_block_visitor<code_fixupper>(parent_,code_fixupper(code_offset_))) {} code_visitor(code_block_visitor<startup_fixup>(parent_,fixup_)) {}
void operator()(object *obj, cell size) void operator()(object *obj, cell size)
{ {
parent->data->tenured->starts.record_object_start_offset(obj); parent->data->tenured->starts.record_object_start_offset(obj);
data_visitor.visit_slots(obj);
switch(obj->type()) switch(obj->type())
{ {
case ALIEN_TYPE: case ALIEN_TYPE:
{ {
cell payload_start = obj->binary_payload_start();
data_visitor.visit_slots(obj,payload_start);
alien *ptr = (alien *)obj; alien *ptr = (alien *)obj;
@ -130,22 +126,11 @@ struct object_fixupper {
} }
case DLL_TYPE: case DLL_TYPE:
{ {
cell payload_start = obj->binary_payload_start();
data_visitor.visit_slots(obj,payload_start);
parent->ffi_dlopen((dll *)obj); parent->ffi_dlopen((dll *)obj);
break; break;
} }
case TUPLE_TYPE:
{
cell payload_start = tuple_size_with_fixup(data_offset,obj);
data_visitor.visit_slots(obj,payload_start);
break;
}
default: default:
{ {
cell payload_start = obj->binary_payload_start();
data_visitor.visit_slots(obj,payload_start);
code_visitor.visit_object_code_block(obj); code_visitor.visit_object_code_block(obj);
break; break;
} }
@ -155,44 +140,51 @@ struct object_fixupper {
void factor_vm::fixup_data(cell data_offset, cell code_offset) 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(); data_workhorse.visit_roots();
object_fixupper fixupper(this,data_offset,code_offset); start_object_updater updater(this,fixup);
fixup_sizer sizer(data_offset); data->tenured->iterate(updater,fixup);
data->tenured->iterate(fixupper,sizer);
} }
struct code_block_fixup_relocation_visitor { struct startup_code_block_relocation_visitor {
factor_vm *parent; factor_vm *parent;
cell code_offset; startup_fixup fixup;
slot_visitor<data_fixupper> data_visitor; slot_visitor<startup_fixup> data_visitor;
code_fixupper code_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_), parent(parent_),
code_offset(code_offset_), fixup(fixup_),
data_visitor(slot_visitor<data_fixupper>(parent_,data_fixupper(data_offset_))), data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)) {}
code_visitor(code_fixupper(code_offset_)) {}
void operator()(instruction_operand op) void operator()(instruction_operand op)
{ {
code_block *compiled = op.parent_code_block(); 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()) switch(op.rel_type())
{ {
case RT_LITERAL: 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:
case RT_ENTRY_POINT_PIC: case RT_ENTRY_POINT_PIC:
case RT_ENTRY_POINT_PIC_TAIL: case RT_ENTRY_POINT_PIC_TAIL:
op.store_code_block(code_visitor(op.load_code_block(old_offset)));
break;
case RT_HERE: 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: case RT_UNTAGGED:
break; break;
default: default:
@ -202,30 +194,28 @@ struct code_block_fixup_relocation_visitor {
} }
}; };
struct code_block_fixupper { struct startup_code_block_updater {
factor_vm *parent; factor_vm *parent;
cell data_offset; startup_fixup fixup;
cell code_offset;
code_block_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) : startup_code_block_updater(factor_vm *parent_, startup_fixup fixup_) :
parent(parent_), parent(parent_), fixup(fixup_) {}
data_offset(data_offset_),
code_offset(code_offset_) {}
void operator()(code_block *compiled, cell size) 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); 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); compiled->each_instruction_operand(code_visitor);
} }
}; };
void factor_vm::fixup_code(cell data_offset, cell code_offset) void factor_vm::fixup_code(cell data_offset, cell code_offset)
{ {
code_block_fixupper fixupper(this,data_offset,code_offset); startup_fixup fixup(data_offset,code_offset);
code->allocator->iterate(fixupper); startup_code_block_updater updater(this,fixup);
code->allocator->iterate(updater,fixup);
} }
/* Read an image file from disk, only done once during startup */ /* 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 */ /* Allocates memory */
code_block *jit::to_code_block() 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(); code.trim();
relocation.trim(); relocation.trim();
parameters.trim(); parameters.trim();

View File

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

View File

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

View File

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

View File

@ -82,13 +82,13 @@ void factor_vm::primitive_size()
ctx->push(allot_cell(object_size(ctx->pop()))); ctx->push(allot_cell(object_size(ctx->pop())));
} }
struct slot_become_visitor { struct slot_become_fixup : no_fixup {
std::map<object *,object *> *become_map; 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_) {} become_map(become_map_) {}
object *operator()(object *old) object *fixup_data(object *old)
{ {
std::map<object *,object *>::const_iterator iter = become_map->find(old); std::map<object *,object *>::const_iterator iter = become_map->find(old);
if(iter != become_map->end()) if(iter != become_map->end())
@ -99,9 +99,9 @@ struct slot_become_visitor {
}; };
struct object_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_) {} workhorse(workhorse_) {}
void operator()(object *obj) void operator()(object *obj)
@ -111,9 +111,9 @@ struct object_become_visitor {
}; };
struct code_block_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_) {} workhorse(workhorse_) {}
void operator()(code_block *compiled, cell size) 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 */ /* 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_roots();
workhorse.visit_contexts(); workhorse.visit_contexts();

View File

@ -1,6 +1,100 @@
namespace factor 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 /* 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 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, 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_roots()
- visit_contexts() */ - visit_contexts() */
template<typename Visitor> struct slot_visitor { template<typename Fixup> struct slot_visitor {
factor_vm *parent; factor_vm *parent;
Visitor visitor; Fixup fixup;
explicit slot_visitor<Visitor>(factor_vm *parent_, Visitor visitor_) : explicit slot_visitor<Fixup>(factor_vm *parent_, Fixup fixup_) :
parent(parent_), visitor(visitor_) {} parent(parent_), fixup(fixup_) {}
cell visit_pointer(cell pointer); cell visit_pointer(cell pointer);
void visit_handle(cell *handle); void visit_handle(cell *handle);
@ -35,35 +129,36 @@ template<typename Visitor> struct slot_visitor {
void visit_callback_roots(); void visit_callback_roots();
void visit_literal_table_roots(); void visit_literal_table_roots();
void visit_roots(); void visit_roots();
void visit_callstack_object(callstack *stack);
void visit_callstack(context *ctx);
void visit_contexts(); void visit_contexts();
void visit_code_block_objects(code_block *compiled); void visit_code_block_objects(code_block *compiled);
void visit_embedded_literals(code_block *compiled); void visit_embedded_literals(code_block *compiled);
}; };
template<typename Visitor> template<typename Fixup>
cell slot_visitor<Visitor>::visit_pointer(cell pointer) cell slot_visitor<Fixup>::visit_pointer(cell pointer)
{ {
if(immediate_p(pointer)) return pointer; if(immediate_p(pointer)) return pointer;
object *untagged = untag<object>(pointer); object *untagged = fixup.fixup_data(untag<object>(pointer));
untagged = visitor(untagged);
return RETAG(untagged,TAG(pointer)); return RETAG(untagged,TAG(pointer));
} }
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_handle(cell *handle) void slot_visitor<Fixup>::visit_handle(cell *handle)
{ {
*handle = visit_pointer(*handle); *handle = visit_pointer(*handle);
} }
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_object_array(cell *start, cell *end) void slot_visitor<Fixup>::visit_object_array(cell *start, cell *end)
{ {
while(start < end) visit_handle(start++); while(start < end) visit_handle(start++);
} }
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_slots(object *ptr, cell payload_start) void slot_visitor<Fixup>::visit_slots(object *ptr, cell payload_start)
{ {
cell *slot = (cell *)ptr; cell *slot = (cell *)ptr;
cell *end = (cell *)((cell)ptr + payload_start); 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> template<typename Fixup>
void slot_visitor<Visitor>::visit_slots(object *ptr) 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> template<typename Fixup>
void slot_visitor<Visitor>::visit_stack_elements(segment *region, cell *top) void slot_visitor<Fixup>::visit_stack_elements(segment *region, cell *top)
{ {
visit_object_array((cell *)region->start,top + 1); visit_object_array((cell *)region->start,top + 1);
} }
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_data_roots() 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 iter = parent->data_roots.begin();
std::vector<data_root_range>::const_iterator end = parent->data_roots.end(); 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); visit_object_array(iter->start,iter->start + iter->len);
} }
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_bignum_roots() void slot_visitor<Fixup>::visit_bignum_roots()
{ {
std::vector<cell>::const_iterator iter = parent->bignum_roots.begin(); std::vector<cell>::const_iterator iter = parent->bignum_roots.begin();
std::vector<cell>::const_iterator end = parent->bignum_roots.end(); 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); cell *handle = (cell *)(*iter);
if(*handle) if(*handle)
*handle = (cell)visitor(*(object **)handle); *handle = (cell)fixup.fixup_data(*(object **)handle);
} }
} }
template<typename Visitor> template<typename Fixup>
struct callback_slot_visitor { struct callback_slot_visitor {
callback_heap *callbacks; 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_) {} callbacks(callbacks_), visitor(visitor_) {}
void operator()(code_block *stub) void operator()(code_block *stub)
@ -126,15 +224,15 @@ struct callback_slot_visitor {
} }
}; };
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_callback_roots() 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); parent->callbacks->each_callback(callback_visitor);
} }
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_literal_table_roots() void slot_visitor<Fixup>::visit_literal_table_roots()
{ {
std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks; std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks;
std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin(); 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; parent->code->uninitialized_blocks = new_uninitialized_blocks;
} }
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_roots() void slot_visitor<Fixup>::visit_roots()
{ {
visit_handle(&parent->true_object); visit_handle(&parent->true_object);
visit_handle(&parent->bignum_zero); 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); visit_object_array(parent->special_objects,parent->special_objects + special_object_count);
} }
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_contexts() 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 begin = parent->active_contexts.begin();
std::set<context *>::const_iterator end = parent->active_contexts.end(); 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->datastack_seg,(cell *)ctx->datastack);
visit_stack_elements(ctx->retainstack_seg,(cell *)ctx->retainstack); visit_stack_elements(ctx->retainstack_seg,(cell *)ctx->retainstack);
visit_object_array(ctx->context_objects,ctx->context_objects + context_object_count); visit_object_array(ctx->context_objects,ctx->context_objects + context_object_count);
visit_callstack(ctx);
begin++; begin++;
} }
} }
template<typename Visitor> template<typename Fixup>
struct literal_references_visitor { 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) void operator()(instruction_operand op)
{ {
@ -197,20 +349,20 @@ struct literal_references_visitor {
} }
}; };
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_code_block_objects(code_block *compiled) void slot_visitor<Fixup>::visit_code_block_objects(code_block *compiled)
{ {
visit_handle(&compiled->owner); visit_handle(&compiled->owner);
visit_handle(&compiled->parameters); visit_handle(&compiled->parameters);
visit_handle(&compiled->relocation); visit_handle(&compiled->relocation);
} }
template<typename Visitor> template<typename Fixup>
void slot_visitor<Visitor>::visit_embedded_literals(code_block *compiled) void slot_visitor<Fixup>::visit_embedded_literals(code_block *compiled)
{ {
if(!parent->code->uninitialized_p(compiled)) if(!parent->code->uninitialized_p(compiled))
{ {
literal_references_visitor<Visitor> visitor(this); literal_references_visitor<Fixup> visitor(this);
compiled->each_instruction_operand(visitor); compiled->each_instruction_operand(visitor);
} }
} }

View File

@ -317,10 +317,11 @@ struct factor_vm
void collect_compact(bool trace_contexts_p); void collect_compact(bool trace_contexts_p);
void collect_growing_heap(cell requested_bytes, 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 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_minor_gc();
void primitive_full_gc(); void primitive_full_gc();
void primitive_compact_gc(); void primitive_compact_gc();
void inline_gc(cell gc_roots);
void primitive_enable_gc_events(); void primitive_enable_gc_events();
void primitive_disable_gc_events(); void primitive_disable_gc_events();
object *allot_object(cell type, cell size); object *allot_object(cell type, cell size);
@ -595,6 +596,7 @@ struct factor_vm
cell frame_executing_quot(stack_frame *frame); cell frame_executing_quot(stack_frame *frame);
stack_frame *frame_successor(stack_frame *frame); stack_frame *frame_successor(stack_frame *frame);
cell frame_scan(stack_frame *frame); cell frame_scan(stack_frame *frame);
cell frame_offset(stack_frame *frame);
void primitive_callstack_to_array(); void primitive_callstack_to_array();
stack_frame *innermost_stack_frame(callstack *stack); stack_frame *innermost_stack_frame(callstack *stack);
void primitive_innermost_stack_frame_executing(); void primitive_innermost_stack_frame_executing();