]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'mongodb-changes' of git://github.com/x6j8x/factor
authorSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Wed, 16 Jun 2010 21:12:13 +0000 (17:12 -0400)
committerSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Wed, 16 Jun 2010 21:12:13 +0000 (17:12 -0400)
85 files changed:
GNUmakefile
Nmakefile
basis/alien/data/data-tests.factor [new file with mode: 0644]
basis/alien/data/data.factor
basis/bootstrap/stage2.factor
basis/classes/struct/struct-tests.factor
basis/classes/struct/struct.factor
basis/compiler/cfg/builder/alien/alien.factor
basis/compiler/cfg/builder/alien/boxing/boxing.factor
basis/compiler/cfg/finalization/finalization.factor
basis/compiler/cfg/gc-checks/gc-checks-tests.factor
basis/compiler/cfg/gc-checks/gc-checks.factor
basis/compiler/cfg/instructions/instructions.factor
basis/compiler/cfg/linear-scan/assignment/assignment.factor
basis/compiler/cfg/liveness/liveness.factor
basis/compiler/cfg/save-contexts/save-contexts.factor
basis/compiler/cfg/ssa/interference/interference-tests.factor
basis/compiler/cfg/stacks/uninitialized/uninitialized-tests.factor
basis/compiler/cfg/stacks/uninitialized/uninitialized.factor
basis/compiler/codegen/fixup/fixup-tests.factor [new file with mode: 0644]
basis/compiler/codegen/fixup/fixup.factor
basis/cpu/architecture/architecture.factor
basis/cpu/x86/32/32.factor
basis/cpu/x86/32/bootstrap.factor
basis/cpu/x86/64/64.factor
basis/cpu/x86/64/bootstrap.factor
basis/cpu/x86/x86.factor
basis/io/sockets/sockets-docs.factor
basis/math/primes/primes-tests.factor
basis/math/primes/primes.factor
basis/math/vectors/simd/cords/cords-tests.factor [new file with mode: 0644]
basis/math/vectors/simd/cords/cords.factor
basis/math/vectors/simd/mirrors/mirrors.factor
basis/mirrors/mirrors.factor
basis/prettyprint/backend/backend.factor
basis/sequences/cords/cords.factor
basis/specialized-arrays/mirrors/mirrors.factor
basis/specialized-arrays/specialized-arrays.factor
basis/specialized-vectors/mirrors/authors.txt [new file with mode: 0644]
basis/specialized-vectors/mirrors/mirrors.factor [new file with mode: 0644]
basis/specialized-vectors/specialized-vectors.factor
basis/tools/disassembler/udis/udis-tests.factor
basis/tools/disassembler/udis/udis.factor
basis/typed/prettyprint/prettyprint.factor
basis/typed/typed-tests.factor
basis/typed/typed.factor
build-support/http-get.vbs
core/vocabs/loader/loader-docs.factor
extra/alien/handles/authors.txt [new file with mode: 0644]
extra/alien/handles/handles-tests.factor [new file with mode: 0644]
extra/alien/handles/handles.factor [new file with mode: 0644]
extra/alien/handles/summary.txt [new file with mode: 0644]
extra/io/encodings/detect/detect-tests.factor
extra/io/encodings/detect/detect.factor
extra/opengl/glu/glu.factor
extra/pop3/pop3-tests.factor
misc/fuel/fuel-font-lock.el
misc/fuel/fuel-syntax.el
vm/bitwise_hacks.hpp
vm/byte_arrays.cpp
vm/byte_arrays.hpp
vm/callstack.cpp
vm/code_block_visitor.hpp
vm/code_blocks.hpp
vm/collector.hpp
vm/compaction.cpp
vm/contexts.cpp
vm/contexts.hpp
vm/data_heap.cpp
vm/fixup.hpp [new file with mode: 0644]
vm/free_list_allocator.hpp
vm/full_collector.cpp
vm/full_collector.hpp
vm/gc.cpp
vm/gc.hpp
vm/gc_info.cpp [new file with mode: 0644]
vm/gc_info.hpp [new file with mode: 0644]
vm/image.cpp
vm/jit.cpp
vm/layouts.hpp
vm/mark_bits.hpp
vm/master.hpp
vm/objects.cpp
vm/slot_visitor.hpp
vm/vm.hpp

index 300a62f71cb8646b2c8560eef2c5d5df8daa3767..89f7ae1446319fa668d35a0c1facba72abfe38a0 100755 (executable)
@@ -46,6 +46,7 @@ ifdef CONFIG
                vm/free_list.o \
                vm/full_collector.o \
                vm/gc.o \
+               vm/gc_info.o \
                vm/image.o \
                vm/inline_cache.o \
                vm/instruction_operands.o \
index 6d9afa1aca8dac23786829ba6311003bf7b49c72..a8b7e103ec21b312b3d862cc57a65671a615c3fb 100755 (executable)
--- a/Nmakefile
+++ b/Nmakefile
@@ -48,6 +48,7 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \
        vm\free_list.obj \
        vm\full_collector.obj \
        vm\gc.obj \
+       vm/gc_info.obj \
        vm\image.obj \
        vm\inline_cache.obj \
        vm\instruction_operands.obj \
diff --git a/basis/alien/data/data-tests.factor b/basis/alien/data/data-tests.factor
new file mode 100644 (file)
index 0000000..20a6c26
--- /dev/null
@@ -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
index 81b53a1b39ee6bb16f935e17d9d85cd0efaee1be..2f5e4b72c6803d0e8404a59137a3f4c254b076c1 100644 (file)
@@ -1,8 +1,9 @@
 ! (c)2009, 2010 Slava Pestov, Joe Groff bsd license
 USING: accessors alien alien.c-types alien.arrays alien.strings
 arrays byte-arrays cpu.architecture fry io io.encodings.binary
-io.files io.streams.memory kernel libc math sequences words
-macros combinators generalizations ;
+io.files io.streams.memory kernel libc math math.functions 
+sequences words macros combinators generalizations ;
+QUALIFIED: math
 IN: alien.data
 
 GENERIC: require-c-array ( c-type -- )
@@ -106,3 +107,12 @@ PRIVATE>
 : with-out-parameters ( c-types quot finish -- values )
     [ [ drop (local-allots) ] [ swap out-parameters ] 2bi ] dip call
     (cleanup-allot) ; inline
+
+GENERIC: binary-zero? ( value -- ? )
+
+M: object binary-zero? drop f ; inline
+M: f binary-zero? drop t ; inline
+M: integer binary-zero? zero? ; inline
+M: math:float binary-zero? double>bits zero? ; inline
+M: complex binary-zero? >rect [ binary-zero? ] both? ; inline
+
index da4fbc444b8f0cad187d96b22d3de51a9a42f32c..e3e8b5ddbc0c7cd6bdc045d7cb8fcc4311186cac 100644 (file)
@@ -58,7 +58,6 @@ SYMBOL: bootstrap-time
     original-error set-global
     error set-global ; inline
 
-
 [
     ! We time bootstrap
     nano-count
index 4ed7d9b446deb1716e6fa17433d0811bc2633fc8..8bdfb8dd57852c049e857904b09e71b02f38f524 100644 (file)
@@ -474,3 +474,4 @@ CONSULT: struct-test-delegate struct-test-delegator del>> ;
         7 >>a
         8 >>b
 ] unit-test
+
index b0f315b3359231830d50f8b7394215d5fe2bb7f3..c15e21f65184650c6063a8c9c62ccf265b67d526 100644 (file)
@@ -231,17 +231,11 @@ M: struct-bit-slot-spec compute-slot-offset
 PRIVATE>
 
 M: struct byte-length class "struct-size" word-prop ; foldable
+M: struct binary-zero? binary-object <direct-uchar-array> [ 0 = ] all? ; inline
 
 ! class definition
 
 <PRIVATE
-GENERIC: binary-zero? ( value -- ? )
-
-M: object binary-zero? drop f ;
-M: f binary-zero? drop t ;
-M: number binary-zero? 0 = ;
-M: struct binary-zero? >c-ptr [ 0 = ] all? ;
-
 : struct-needs-prototype? ( class -- ? )
     struct-slots [ initial>> binary-zero? ] all? not ;
 
index 7bf45e959a238ed95962fa1ae12bcffb34ca5044..04ac2bf4969d78ab1052063e84e230992f54818a 100644 (file)
@@ -102,7 +102,7 @@ M: #alien-invoke emit-node
     [
         {
             [ caller-parameters ]
-            [ ##prepare-var-args alien-invoke-dlsym ##alien-invoke ]
+            [ ##prepare-var-args alien-invoke-dlsym <gc-map> ##alien-invoke ]
             [ emit-stack-frame ]
             [ box-return* ]
         } cleave
@@ -111,7 +111,7 @@ M: #alien-invoke emit-node
 M:: #alien-indirect emit-node ( node -- )
     node [
         D 0 ^^peek -1 ##inc-d ^^unbox-any-c-ptr :> src
-        [ caller-parameters src ##alien-indirect ]
+        [ caller-parameters src <gc-map> ##alien-indirect ]
         [ emit-stack-frame ]
         [ box-return* ]
         tri
index 6f5f46b9c10db519c104aa409ae6241dd4f0c02b..1992d7539a19ebe2baefa98abe16b836da091be3 100644 (file)
@@ -105,13 +105,13 @@ M: struct-c-type flatten-parameter-type frob-struct flatten-c-type ;
 GENERIC: box ( vregs reps c-type -- dst )
 
 M: c-type box
-    [ first ] [ drop ] [ [ boxer>> ] [ rep>> ] bi ] tri* ^^box ;
+    [ first ] [ drop ] [ [ boxer>> ] [ rep>> ] bi ] tri* <gc-map> ^^box ;
 
 M: long-long-type box
-    [ first2 ] [ drop ] [ boxer>> ] tri* ^^box-long-long ;
+    [ first2 ] [ drop ] [ boxer>> ] tri* <gc-map> ^^box-long-long ;
 
 M: struct-c-type box
-    '[ _ heap-size ^^allot-byte-array dup ^^unbox-byte-array ] 2dip
+    '[ _ heap-size <gc-map> ^^allot-byte-array dup ^^unbox-byte-array ] 2dip
     implode-struct ;
 
 GENERIC: box-parameter ( vregs reps c-type -- dst )
index 5440ba6eef6924936c118cd77a73f5266f1c1e9f..83bcc0b0b1b542347b8859a32228a812ccd14ea4 100644 (file)
@@ -1,15 +1,17 @@
 ! Copyright (C) 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: compiler.cfg.gc-checks compiler.cfg.representations
-compiler.cfg.save-contexts compiler.cfg.ssa.destruction
-compiler.cfg.build-stack-frame compiler.cfg.linear-scan
-compiler.cfg.scheduling ;
+USING: kernel compiler.cfg.gc-checks
+compiler.cfg.representations compiler.cfg.save-contexts
+compiler.cfg.ssa.destruction compiler.cfg.build-stack-frame
+compiler.cfg.linear-scan compiler.cfg.scheduling
+compiler.cfg.stacks.uninitialized ;
 IN: compiler.cfg.finalization
 
 : finalize-cfg ( cfg -- cfg' )
     select-representations
     schedule-instructions
     insert-gc-checks
+    dup compute-uninitialized-sets
     insert-save-contexts
     destruct-ssa
     linear-scan
index 496954de2c83cd87d6c51a7e1a251cc6b39b3730..d8745c0784f5d4d2c11d698c60ec0945ad51dbb4 100644 (file)
@@ -29,14 +29,6 @@ V{
 
 2 \ vreg-counter set-global
 
-[
-    V{
-        T{ ##load-tagged f 3 0 }
-        T{ ##replace f 3 D 0 }
-        T{ ##replace f 3 R 3 }
-    }
-] [ [ { D 0 R 3 } wipe-locs ] V{ } make ] unit-test
-
 : gc-check? ( bb -- ? )
     instructions>>
     {
@@ -50,15 +42,12 @@ V{
 
 [
     V{
-        T{ ##load-tagged f 5 0 }
-        T{ ##replace f 5 D 0 }
-        T{ ##replace f 5 R 3 }
-        T{ ##call-gc f { 0 1 2 } }
+        T{ ##call-gc f T{ gc-map } }
         T{ ##branch }
     }
 ]
 [
-    { D 0 R 3 } { 0 1 2 } <gc-call> instructions>>
+    <gc-call> instructions>>
 ] unit-test
 
 30 \ vreg-counter set-global
@@ -92,7 +81,7 @@ V{
 
 [ ] [ cfg get needs-predecessors drop ] unit-test
 
-[ ] [ { D 1 R 2 } { 10 20 } V{ } 31337 3 get (insert-gc-check) ] unit-test
+[ ] [ V{ } 31337 3 get (insert-gc-check) ] unit-test
 
 [ t ] [ 1 get successors>> first gc-check? ] unit-test
 
@@ -156,11 +145,7 @@ H{
 
 [
     V{
-        T{ ##load-tagged f 31 0 }
-        T{ ##replace f 31 D 0 }
-        T{ ##replace f 31 D 1 }
-        T{ ##replace f 31 D 2 }
-        T{ ##call-gc f { 2 } }
+        T{ ##call-gc f T{ gc-map } }
         T{ ##branch }
     }
 ] [ 2 get predecessors>> second instructions>> ] unit-test
index 255e5476e684992d433e6ef530d12f204422fb0d..50cd67567c6fef82e70d6b27178303278073ebf7 100644 (file)
@@ -9,10 +9,7 @@ compiler.cfg.registers
 compiler.cfg.utilities
 compiler.cfg.comparisons
 compiler.cfg.instructions
-compiler.cfg.predecessors
-compiler.cfg.liveness
-compiler.cfg.liveness.ssa
-compiler.cfg.stacks.uninitialized ;
+compiler.cfg.predecessors ;
 IN: compiler.cfg.gc-checks
 
 <PRIVATE
@@ -50,16 +47,9 @@ IN: compiler.cfg.gc-checks
         ] bi*
     ] V{ } make >>instructions ;
 
-: wipe-locs ( uninitialized-locs -- )
-    '[
-        int-rep next-vreg-rep
-        [ 0 ##load-tagged ]
-        [ '[ [ _ ] dip ##replace ] each ] bi
-    ] unless-empty ;
-
-: <gc-call> ( uninitialized-locs gc-roots -- bb )
-    [ <basic-block> ] 2dip
-    [ [ wipe-locs ] [ ##call-gc ] bi* ##branch ] V{ } make
+: <gc-call> ( -- bb )
+    <basic-block>
+    [ <gc-map> ##call-gc ##branch ] V{ } make
     >>instructions t >>unlikely? ;
 
 :: insert-guard ( body check bb -- )
@@ -73,7 +63,7 @@ IN: compiler.cfg.gc-checks
 
     check predecessors>> [ bb check update-successors ] each ;
 
-: (insert-gc-check) ( uninitialized-locs gc-roots phis size bb -- )
+: (insert-gc-check) ( phis size bb -- )
     [ [ <gc-call> ] 2dip <gc-check> ] dip insert-guard ;
 
 GENERIC: allocation-size* ( insn -- n )
@@ -89,35 +79,17 @@ M: ##box-displaced-alien allocation-size* drop 5 cells ;
     [ ##allocation? ] filter
     [ allocation-size* data-alignment get align ] map-sum ;
 
-: gc-live-in ( bb -- vregs )
-    [ live-in keys ] [ instructions>> [ ##phi? ] filter [ dst>> ] map ] bi
-    append ;
-
-: live-tagged ( bb -- vregs )
-    gc-live-in [ rep-of tagged-rep? ] filter ;
-
 : remove-phis ( bb -- phis )
     [ [ ##phi? ] partition ] change-instructions drop ;
 
 : insert-gc-check ( bb -- )
-    {
-        [ uninitialized-locs ]
-        [ live-tagged ]
-        [ remove-phis ]
-        [ allocation-size ]
-        [ ]
-    } cleave
-    (insert-gc-check) ;
+    [ remove-phis ] [ allocation-size ] [ ] tri (insert-gc-check) ;
 
 PRIVATE>
 
 : insert-gc-checks ( cfg -- cfg' )
     dup blocks-with-gc [
-        [
-            needs-predecessors
-            dup compute-ssa-live-sets
-            dup compute-uninitialized-sets
-        ] dip
+        [ needs-predecessors ] dip
         [ insert-gc-check ] each
         cfg-changed
     ] unless-empty ;
index e05335b06c00ea4c2f3c41ddba34e61ce934cd95..39d2ab81cd557507b3661e03970e7e400ea77f0f 100644 (file)
@@ -670,27 +670,28 @@ literal: size align offset ;
 INSN: ##box
 def: dst/tagged-rep
 use: src
-literal: boxer rep ;
+literal: boxer rep gc-map ;
 
 INSN: ##box-long-long
 def: dst/tagged-rep
 use: src1/int-rep src2/int-rep
-literal: boxer ;
+literal: boxer gc-map ;
 
 INSN: ##allot-byte-array
 def: dst/tagged-rep
-literal: size ;
+literal: size gc-map ;
 
 INSN: ##prepare-var-args ;
 
 INSN: ##alien-invoke
-literal: symbols dll ;
+literal: symbols dll gc-map ;
 
 INSN: ##cleanup
 literal: n ;
 
 INSN: ##alien-indirect
-use: src/int-rep ;
+use: src/int-rep
+literal: gc-map ;
 
 INSN: ##alien-assembly
 literal: quot ;
@@ -819,8 +820,7 @@ INSN: ##check-nursery-branch
 literal: size cc
 temp: temp1/int-rep temp2/int-rep ;
 
-INSN: ##call-gc
-literal: gc-roots ;
+INSN: ##call-gc literal: gc-map ;
 
 ! Spills and reloads, inserted by register allocator
 TUPLE: spill-slot { n integer } ;
@@ -858,6 +858,23 @@ UNION: conditional-branch-insn
 UNION: ##read ##slot ##slot-imm ##vm-field ##alien-global ;
 UNION: ##write ##set-slot ##set-slot-imm ##set-vm-field ;
 
+! Instructions that contain subroutine calls to functions which
+! allocate memory
+UNION: gc-map-insn
+##call-gc
+##alien-invoke
+##alien-indirect
+##box
+##box-long-long
+##allot-byte-array ;
+
+M: gc-map-insn clone call-next-method [ clone ] change-gc-map ;
+
+! Each one has a gc-map slot
+TUPLE: gc-map scrub-d scrub-r gc-roots ;
+
+: <gc-map> ( -- gc-map ) gc-map new ;
+
 ! Instructions that clobber registers. They receive inputs and
 ! produce outputs in spill slots.
 UNION: hairy-clobber-insn
index 1780a1c907793d46a857ab3e21c9f6107253d052..cab4438ec9b189ff54ea2073fafdaa16aae71af5 100644 (file)
@@ -142,9 +142,10 @@ RENAMING: assign [ vreg>reg ] [ vreg>reg ] [ vreg>reg ]
 M: vreg-insn assign-registers-in-insn
     [ assign-insn-defs ] [ assign-insn-uses ] [ assign-insn-temps ] tri ;
 
-M: ##call-gc assign-registers-in-insn
-    dup call-next-method
-    [ [ vreg>reg ] map ] change-gc-roots drop ;
+M: gc-map-insn assign-registers-in-insn
+    [ [ assign-insn-defs ] [ assign-insn-uses ] [ assign-insn-temps ] tri ]
+    [ gc-map>> [ [ vreg>reg ] map ] change-gc-roots drop ]
+    bi ;
 
 M: insn assign-registers-in-insn drop ;
 
index a10b48cc0ce034332acc1dbda673ca6d11290b59..1a5287355d63363307e311f6c90b8fde4226c5fa 100644 (file)
@@ -1,25 +1,40 @@
-! Copyright (C) 2009 Slava Pestov.
+! Copyright (C) 2009, 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel accessors assocs sequences sets
 compiler.cfg.def-use compiler.cfg.dataflow-analysis
-compiler.cfg.instructions ;
+compiler.cfg.instructions compiler.cfg.registers
+cpu.architecture ;
 IN: compiler.cfg.liveness
 
 ! See http://en.wikipedia.org/wiki/Liveness_analysis
-! Do not run after SSA construction
+! Do not run after SSA construction; compiler.cfg.liveness.ssa
+! should be used instead. The transfer-liveness word is used
+! by SSA liveness too, so it handles ##phi instructions.
 
 BACKWARD-ANALYSIS: live
 
-GENERIC: insn-liveness ( live-set insn -- )
+GENERIC: visit-insn ( live-set insn -- live-set )
 
 : kill-defs ( live-set insn -- live-set )
-    defs-vreg [ over delete-at ] when* ;
+    defs-vreg [ over delete-at ] when* ; inline
 
 : gen-uses ( live-set insn -- live-set )
-    dup ##phi? [ drop ] [ uses-vregs [ over conjoin ] each ] if ;
+    uses-vregs [ over conjoin ] each ; inline
+
+M: vreg-insn visit-insn [ kill-defs ] [ gen-uses ] bi ;
+
+: fill-gc-map ( live-set insn -- live-set )
+    gc-map>> over keys [ rep-of tagged-rep? ] filter >>gc-roots drop ;
+
+M: gc-map-insn visit-insn
+    [ kill-defs ] [ fill-gc-map ] [ gen-uses ] tri ;
+
+M: ##phi visit-insn kill-defs ;
+
+M: insn visit-insn drop ;
 
 : transfer-liveness ( live-set instructions -- live-set' )
-    [ clone ] [ <reversed> ] bi* [ [ kill-defs ] [ gen-uses ] bi ] each ;
+    [ clone ] [ <reversed> ] bi* [ visit-insn ] each ;
 
 : local-live-in ( instructions -- live-set )
     [ H{ } ] dip transfer-liveness keys ;
index e5edd7cdffb37fa296b9d28d0139df313e8ba2e1..e2ccf943ad93405fcdb28d8e8903d6096130a85b 100644 (file)
@@ -10,7 +10,6 @@ IN: compiler.cfg.save-contexts
 : needs-save-context? ( insns -- ? )
     [
         {
-            [ ##call-gc? ]
             [ ##unary-float-function? ]
             [ ##binary-float-function? ]
             [ ##alien-invoke? ]
index 4e3da1c6dcf1fea0fd640562714133d3dac8ff9a..36c03bc6af192bb540f9c768f3a4209ed8f20141 100644 (file)
@@ -182,7 +182,7 @@ V{
 
 V{
     T{ ##save-context f 77 78 }
-    T{ ##call-gc f { } }
+    T{ ##call-gc f T{ gc-map } }
     T{ ##branch }
 } 2 test-bb
 
index 61c3cd67d1ffc5a309b1026d22867c74c37d47bb..fb9c83313683f3bd879cd548e9fc8e784011ee53 100644 (file)
@@ -29,8 +29,8 @@ V{
 
 [ ] [ test-uninitialized ] unit-test
 
-[ V{ D 0 D 1 D 2 } ] [ 1 get uninitialized-locs ] unit-test
-[ V{ R 0 } ] [ 2 get uninitialized-locs ] unit-test
+[ { B{ 0 0 0 } B{ } } ] [ 1 get uninitialized-in ] unit-test
+[ { B{ 1 1 1 } B{ 0 } } ] [ 2 get uninitialized-in ] unit-test
 
 ! When merging, if a location is uninitialized in one branch and
 ! initialized in another, we have to consider it uninitialized,
@@ -57,4 +57,4 @@ V{
 
 [ ] [ test-uninitialized ] unit-test
 
-[ V{ D 0 } ] [ 3 get uninitialized-locs ] unit-test
+[ { B{ 0 } B{ } } ] [ 3 get uninitialized-in ] unit-test
index 3d7519e14ba9e79dcbaeba863af4ece84c793c74..7498cddf109e7e1a4b74214192c520566525b7d8 100644 (file)
@@ -9,11 +9,17 @@ IN: compiler.cfg.stacks.uninitialized
 
 ! Consider the following sequence of instructions:
 ! ##inc-d 2
-! ##gc
+! ...
+! ##allot
 ! ##replace ... D 0
 ! ##replace ... D 1
-! The GC check runs before stack locations 0 and 1 have been initialized,
-! and it needs to zero them out so that GC doesn't try to trace them.
+! The GC check runs before stack locations 0 and 1 have been
+! initialized, and so the GC needs to scrub them so that they
+! don't get traced. This is achieved by computing uninitialized
+! locations with a dataflow analysis, and recording the
+! information in GC maps. The scrub_contexts() method on
+! vm/gc.cpp reads this information from GC maps and performs
+! the scrubbing.
 
 <PRIVATE
 
@@ -28,7 +34,6 @@ GENERIC: visit-insn ( insn -- )
     ] change ;
 
 M: ##inc-d visit-insn n>> ds-loc handle-inc ;
-
 M: ##inc-r visit-insn n>> rs-loc handle-inc ;
 
 ERROR: uninitialized-peek insn ;
@@ -46,6 +51,12 @@ M: ##peek visit-insn visit-peek ;
 M: ##replace visit-insn visit-replace ;
 M: ##replace-imm visit-insn visit-replace ;
 
+M: gc-map-insn visit-insn
+    gc-map>>
+    ds-loc get clone >>scrub-d
+    rs-loc get clone >>scrub-r
+    drop ;
+
 M: insn visit-insn drop ;
 
 : prepare ( pair -- )
@@ -59,9 +70,6 @@ M: insn visit-insn drop ;
 : (join-sets) ( seq1 seq2 -- seq )
     2dup [ length ] bi@ max '[ _ 1 pad-tail ] bi@ [ bitand ] 2map ;
 
-: (uninitialized-locs) ( seq quot -- seq' )
-    [ [ drop 0 = ] selector [ each-index ] dip ] dip map ; inline
-
 PRIVATE>
 
 FORWARD-ANALYSIS: uninitialized
@@ -71,11 +79,3 @@ M: uninitialized-analysis transfer-set ( pair bb analysis -- pair' )
 
 M: uninitialized-analysis join-sets ( sets analysis -- pair )
     2drop sift [ f ] [ [ ] [ [ (join-sets) ] 2map ] map-reduce ] if-empty ;
-
-: uninitialized-locs ( bb -- locs )
-    uninitialized-in dup [
-        first2
-        [ [ <ds-loc> ] (uninitialized-locs) ]
-        [ [ <rs-loc> ] (uninitialized-locs) ]
-        bi* append
-    ] when ;
diff --git a/basis/compiler/codegen/fixup/fixup-tests.factor b/basis/compiler/codegen/fixup/fixup-tests.factor
new file mode 100644 (file)
index 0000000..f068861
--- /dev/null
@@ -0,0 +1,72 @@
+USING: namespaces byte-arrays make compiler.codegen.fixup
+bit-arrays accessors classes.struct tools.test kernel math
+sequences alien.c-types specialized-arrays boxes
+compiler.cfg.instructions system cpu.architecture ;
+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 } ;
+
+SINGLETON: fake-cpu
+
+fake-cpu \ cpu set
+
+M: fake-cpu gc-root-offsets ;
+
+[ ] [
+    [
+        init-fixup
+
+        50 <byte-array> %
+
+        T{ gc-map f B{ } B{ } V{ } } gc-map-here
+
+        50 <byte-array> %
+
+        T{ gc-map f B{ 0 1 1 1 0 } B{ 1 0 } V{ 1 3 } } 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
index 9e366cd40833c0f8cd220da8c0d58f820e79d9dd..b4ef317b677a523ae04af74732d862f4ab173538 100644 (file)
@@ -1,10 +1,12 @@
 ! Copyright (C) 2007, 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: arrays byte-arrays byte-vectors generic assocs hashtables
-io.binary kernel kernel.private math namespaces make sequences
-words quotations strings alien.accessors alien.strings layouts
-system combinators math.bitwise math.order combinators.smart
-accessors growable fry compiler.constants memoize ;
+USING: arrays bit-arrays byte-arrays byte-vectors generic assocs
+hashtables io.binary kernel kernel.private math namespaces make
+sequences words quotations strings alien.accessors alien.strings
+layouts system combinators math.bitwise math.order
+combinators.short-circuit combinators.smart accessors growable
+fry memoize compiler.constants compiler.cfg.instructions
+cpu.architecture ;
 IN: compiler.codegen.fixup
 
 ! Utilities
@@ -95,7 +97,7 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ;
 : rel-decks-offset ( class -- )
     rt-decks-offset rel-fixup ;
 
-! And the rest
+! Labels
 : compute-target ( label-fixup -- offset )
     label>> offset>> [ "Unresolved label" throw ] unless* ;
 
@@ -112,13 +114,7 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ;
     [ [ compute-relative-label ] map concat ]
     bi* ;
 
-: init-fixup ( -- )
-    V{ } clone parameter-table set
-    V{ } clone literal-table set
-    V{ } clone label-table set
-    BV{ } clone relocation-table set
-    V{ } clone binary-literal-table set ;
-
+! Binary literals
 : alignment ( align -- n )
     [ compiled-offset dup ] dip align swap - ;
 
@@ -136,16 +132,107 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ;
 : emit-binary-literals ( -- )
     binary-literal-table get [ emit-data ] assoc-each ;
 
+! GC info
+
+! Every code block either ends with
+!
+! uint 0
+!
+! or
+!
+! bitmap, byte aligned, three subsequences:
+! - <scrubbed data stack locations>
+! - <scrubbed retain stack locations>
+! - <GC root spill slots>
+! uint[] <return addresses>
+! uint <largest scrubbed data stack location>
+! uint <largest scrubbed retain stack location>
+! uint <largest GC root spill slot>
+! uint <number of return addresses>
+
+SYMBOLS: return-addresses gc-maps ;
+
+: gc-map-needed? ( gc-map -- ? )
+    ! If there are no stack locations to scrub and no GC roots,
+    ! there's no point storing the GC map.
+    dup [
+        {
+            [ scrub-d>> empty? ]
+            [ scrub-r>> empty? ]
+            [ gc-roots>> empty? ]
+        } 1&& not
+    ] when ;
+
+: gc-map-here ( gc-map -- )
+    dup gc-map-needed? [
+        gc-maps get push
+        compiled-offset return-addresses get push
+    ] [ drop ] if ;
+
+: emit-scrub ( seqs -- n )
+    ! seqs is a sequence of sequences of 0/1
+    dup [ length ] [ max ] map-reduce
+    [ '[ [ 0 = ] ?{ } map-as _ f pad-tail % ] each ] keep ;
+
+: integers>bits ( seq n -- bit-array )
+    <bit-array> [ '[ [ t ] dip _ set-nth ] each ] keep ;
+
+: emit-gc-roots ( seqs -- n )
+    ! seqs is a sequence of sequences of integers 0..n-1
+    dup [ [ 0 ] [ supremum 1 + ] if-empty ] [ max ] map-reduce
+    [ '[ _ integers>bits % ] each ] keep ;
+
+: emit-uint ( n -- )
+    building get push-uint ;
+
+: gc-info ( -- byte-array )
+    [
+        return-addresses get empty? [ 0 emit-uint ] [
+            gc-maps get
+            [
+                [ [ scrub-d>> ] map emit-scrub ]
+                [ [ scrub-r>> ] map emit-scrub ]
+                [ [ gc-roots>> gc-root-offsets ] map emit-gc-roots ] 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 ;
+
+: check-fixup ( seq -- )
+    length data-alignment get mod 0 assert= ;
+
 : with-fixup ( quot -- code )
     '[
+        init-fixup
         [
-            init-fixup
             @
             emit-binary-literals
+            emit-gc-info
             label-table [ compute-labels ] change
             parameter-table get >array
             literal-table get >array
             relocation-table get >byte-array
             label-table get
         ] B{ } make
+        dup check-fixup
     ] output>array ; inline
index e2a7bdab10cb7ae9ec30fdd1b964397d0c5227a9..931dccece123d5b69b6707e8680182ed64be15b2 100644 (file)
@@ -225,6 +225,8 @@ M: object vm-stack-space 0 ;
 ! %store-memory work
 HOOK: complex-addressing? cpu ( -- ? )
 
+HOOK: gc-root-offsets cpu ( seq -- seq' )
+
 HOOK: %load-immediate cpu ( reg val -- )
 HOOK: %load-reference cpu ( reg obj -- )
 HOOK: %load-float cpu ( reg val -- )
@@ -488,7 +490,7 @@ HOOK: %write-barrier-imm cpu ( src slot tag temp1 temp2 -- )
 
 ! GC checks
 HOOK: %check-nursery-branch cpu ( label size cc temp1 temp2 -- )
-HOOK: %call-gc cpu ( gc-roots -- )
+HOOK: %call-gc cpu ( gc-map -- )
 
 HOOK: %prologue cpu ( n -- )
 HOOK: %epilogue cpu ( n -- )
@@ -594,11 +596,11 @@ HOOK: %local-allot cpu ( dst size align offset -- )
 ! Call a function to convert a value into a tagged pointer,
 ! possibly allocating a bignum, float, or alien instance,
 ! which is then pushed on the data stack
-HOOK: %box cpu ( dst src func rep -- )
+HOOK: %box cpu ( dst src func rep gc-map -- )
 
-HOOK: %box-long-long cpu ( dst src1 src2 func -- )
+HOOK: %box-long-long cpu ( dst src1 src2 func gc-map -- )
 
-HOOK: %allot-byte-array cpu ( dst size -- )
+HOOK: %allot-byte-array cpu ( dst size gc-map -- )
 
 HOOK: %restore-context cpu ( temp1 temp2 -- )
 
@@ -608,13 +610,13 @@ HOOK: %prepare-var-args cpu ( -- )
 
 M: object %prepare-var-args ;
 
-HOOK: %alien-invoke cpu ( function library -- )
+HOOK: %alien-invoke cpu ( function library gc-map -- )
 
 HOOK: %cleanup cpu ( n -- )
 
 M: object %cleanup ( n -- ) drop ;
 
-HOOK: %alien-indirect cpu ( src -- )
+HOOK: %alien-indirect cpu ( src gc-map -- )
 
 HOOK: %load-reg-param cpu ( dst reg rep -- )
 
index 481293759701a565c89a8a5d1fc8e9a73a734c9c..48cc88a4f86eeb97ddfca4de8f417768dc7cb62a 100755 (executable)
@@ -56,20 +56,6 @@ M: x86.32 %mark-deck
     rc-absolute-cell rel-decks-offset
     building get push ;
 
-M:: x86.32 %dispatch ( src temp -- )
-    ! Load jump table base.
-    temp src HEX: ffffffff [+] LEA
-    building get length :> start
-    0 rc-absolute-cell rel-here
-    ! Go
-    temp HEX: 7f [+] JMP
-    building get length :> end
-    ! Fix up the displacement above
-    cell alignment
-    [ end start - + building get dup pop* push ]
-    [ (align-code) ]
-    bi ;
-
 M: x86.32 pic-tail-reg EDX ;
 
 M: x86.32 reserved-stack-space 0 ;
@@ -148,7 +134,7 @@ M: x86.32 %store-reg-param ( src reg rep -- )
     EAX src tagged-rep %copy
     4 save-vm-ptr
     0 stack@ EAX MOV
-    func f %alien-invoke ;
+    func f %alien-invoke ;
 
 M:: x86.32 %unbox ( dst src func rep -- )
     src func call-unbox-func
@@ -160,36 +146,37 @@ M:: x86.32 %unbox-long-long ( src out func -- )
     EAX out int-rep %copy
     4 stack@ EAX MOV
     8 save-vm-ptr
-    func f %alien-invoke ;
+    func f %alien-invoke ;
 
-M:: x86.32 %box ( dst src func rep -- )
+M:: x86.32 %box ( dst src func rep gc-map -- )
     rep rep-size save-vm-ptr
     src rep %store-return
     0 stack@ rep %load-return
-    func f %alien-invoke
+    func f gc-map %alien-invoke
     dst EAX tagged-rep %copy ;
 
-M:: x86.32 %box-long-long ( dst src1 src2 func -- )
+M:: x86.32 %box-long-long ( dst src1 src2 func gc-map -- )
     8 save-vm-ptr
     EAX src1 int-rep %copy
     0 stack@ EAX int-rep %copy
     EAX src2 int-rep %copy
     4 stack@ EAX int-rep %copy
-    func f %alien-invoke
+    func f gc-map %alien-invoke
     dst EAX tagged-rep %copy ;
 
-M:: x86.32 %allot-byte-array ( dst size -- )
+M:: x86.32 %allot-byte-array ( dst size gc-map -- )
     4 save-vm-ptr
     0 stack@ size MOV
-    "allot_byte_array" f %alien-invoke
+    "allot_byte_array" f gc-map %alien-invoke
     dst EAX tagged-rep %copy ;
 
-M: x86.32 %alien-invoke 0 CALL rc-relative rel-dlsym ;
+M: x86.32 %alien-invoke
+    [ 0 CALL rc-relative rel-dlsym ] dip gc-map-here ;
 
 M: x86.32 %begin-callback ( -- )
     0 save-vm-ptr
     4 stack@ 0 MOV
-    "begin_callback" f %alien-invoke ;
+    "begin_callback" f %alien-invoke ;
 
 M: x86.32 %alien-callback ( quot -- )
     [ EAX ] dip %load-reference
@@ -197,7 +184,7 @@ M: x86.32 %alien-callback ( quot -- )
 
 M: x86.32 %end-callback ( -- )
     0 save-vm-ptr
-    "end_callback" f %alien-invoke ;
+    "end_callback" f %alien-invoke ;
 
 GENERIC: float-function-param ( n dst src -- )
 
@@ -212,13 +199,13 @@ M:: register float-function-param ( n dst src -- )
 
 M:: x86.32 %unary-float-function ( dst src func -- )
     0 dst src float-function-param
-    func "libm" load-library %alien-invoke
+    func "libm" load-library %alien-invoke
     dst double-rep %load-return ;
 
 M:: x86.32 %binary-float-function ( dst src1 src2 func -- )
     0 dst src1 float-function-param
     8 dst src2 float-function-param
-    func "libm" load-library %alien-invoke
+    func "libm" load-library %alien-invoke
     dst double-rep %load-return ;
 
 : funny-large-struct-return? ( return abi -- ? )
@@ -239,11 +226,6 @@ M:: x86.32 stack-cleanup ( stack-size return abi -- n )
 M: x86.32 %cleanup ( n -- )
     [ ESP swap SUB ] unless-zero ;
 
-M:: x86.32 %call-gc ( gc-roots -- )
-    4 save-vm-ptr
-    0 stack@ gc-roots gc-root-offsets %load-reference
-    "inline_gc" f %alien-invoke ;
-
 M: x86.32 dummy-stack-params? f ;
 
 M: x86.32 dummy-int-params? f ;
index a52a3390acd150f9f999855e6b819004abafd2f1..2b82fa81178521b284afc834247d4b113d337a54 100644 (file)
@@ -63,6 +63,9 @@ IN: bootstrap.x86
     ds-reg ctx-reg context-datastack-offset [+] MOV
     rs-reg ctx-reg context-retainstack-offset [+] MOV ;
 
+: jit-scrub-return ( n -- )
+    ESP swap [+] 0 MOV ;
+
 [
     ! ctx-reg is preserved across the call because it is non-volatile
     ! in the C ABI
@@ -130,6 +133,7 @@ IN: bootstrap.x86
 
     ! Unwind stack frames
     ESP EDX MOV
+    0 jit-scrub-return
 
     jit-jump-quot
 ] \ unwind-native-frames define-sub-primitive
@@ -252,6 +256,8 @@ IN: bootstrap.x86
 
 ! Contexts
 : jit-switch-context ( reg -- )
+    -4 jit-scrub-return
+
     ! Save ds, rs registers
     jit-load-vm
     jit-save-context
index bde0507af971b746dde6b9139788e889641c0250..7a5e8a1af3138b8a50223e3a66c623a6ce7c21a1 100644 (file)
@@ -81,21 +81,6 @@ M: x86.64 %mark-deck
     dup load-decks-offset
     [+] card-mark <byte> MOV ;
 
-M:: x86.64 %dispatch ( src temp -- )
-    ! Load jump table base.
-    temp HEX: ffffffff MOV
-    building get length :> start
-    0 rc-absolute-cell rel-here
-    ! Add jump table base
-    temp src ADD
-    temp HEX: 7f [+] JMP
-    building get length :> end
-    ! Fix up the displacement above
-    cell alignment
-    [ end start - + building get dup pop* push ]
-    [ (align-code) ]
-    bi ;
-
 M:: x86.64 %load-reg-param ( dst reg rep -- )
     dst reg rep %copy ;
 
@@ -105,30 +90,29 @@ M:: x86.64 %store-reg-param ( src reg rep -- )
 M:: x86.64 %unbox ( dst src func rep -- )
     param-reg-0 src tagged-rep %copy
     param-reg-1 %mov-vm-ptr
-    func f %alien-invoke
+    func f %alien-invoke
     dst rep %load-return ;
 
-M:: x86.64 %box ( dst src func rep -- )
+M:: x86.64 %box ( dst src func rep gc-map -- )
     0 rep reg-class-of cdecl param-regs at nth src rep %copy
     rep int-rep? os windows? or param-reg-1 param-reg-0 ? %mov-vm-ptr
-    func f %alien-invoke
+    func f gc-map %alien-invoke
     dst int-rep %load-return ;
 
-M:: x86.64 %allot-byte-array ( dst size -- )
+M:: x86.64 %allot-byte-array ( dst size gc-map -- )
     param-reg-0 size MOV
     param-reg-1 %mov-vm-ptr
-    "allot_byte_array" f %alien-invoke
+    "allot_byte_array" f gc-map %alien-invoke
     dst int-rep %load-return ;
 
 M: x86.64 %alien-invoke
-    R11 0 MOV
-    rc-absolute-cell rel-dlsym
-    R11 CALL ;
+    [ R11 0 MOV rc-absolute-cell rel-dlsym R11 CALL ] dip
+    gc-map-here ;
 
 M: x86.64 %begin-callback ( -- )
     param-reg-0 %mov-vm-ptr
     param-reg-1 0 MOV
-    "begin_callback" f %alien-invoke ;
+    "begin_callback" f %alien-invoke ;
 
 M: x86.64 %alien-callback ( quot -- )
     [ param-reg-0 ] dip %load-reference
@@ -136,14 +120,14 @@ M: x86.64 %alien-callback ( quot -- )
 
 M: x86.64 %end-callback ( -- )
     param-reg-0 %mov-vm-ptr
-    "end_callback" f %alien-invoke ;
+    "end_callback" f %alien-invoke ;
 
 : float-function-param ( i src -- )
     [ float-regs cdecl param-regs at nth ] dip double-rep %copy ;
 
 M:: x86.64 %unary-float-function ( dst src func -- )
     0 src float-function-param
-    func "libm" load-library %alien-invoke
+    func "libm" load-library %alien-invoke
     dst double-rep %load-return ;
 
 M:: x86.64 %binary-float-function ( dst src1 src2 func -- )
@@ -151,14 +135,9 @@ M:: x86.64 %binary-float-function ( dst src1 src2 func -- )
     ! src2 is always a spill slot
     0 src1 float-function-param
     1 src2 float-function-param
-    func "libm" load-library %alien-invoke
+    func "libm" load-library %alien-invoke
     dst double-rep %load-return ;
 
-M:: x86.64 %call-gc ( gc-roots -- )
-    param-reg-0 gc-roots gc-root-offsets %load-reference
-    param-reg-1 %mov-vm-ptr
-    "inline_gc" f %alien-invoke ;
-
 M: x86.64 long-long-on-stack? f ;
 
 M: x86.64 float-on-stack? f ;
index 393d1c9b8bf1e5afe74e530ce63643eeabb149a5..e81e92424555f8b28ce6abc6255af13c32215eef 100644 (file)
@@ -61,6 +61,9 @@ IN: bootstrap.x86
     ds-reg ctx-reg context-datastack-offset [+] MOV
     rs-reg ctx-reg context-retainstack-offset [+] MOV ;
 
+: jit-scrub-return ( n -- )
+    RSP swap [+] 0 MOV ;
+
 [
     ! ctx-reg is preserved across the call because it is non-volatile
     ! in the C ABI
@@ -111,6 +114,7 @@ IN: bootstrap.x86
 
     ! Unwind stack frames
     RSP arg2 MOV
+    0 jit-scrub-return
 
     ! Load VM pointer into vm-reg, since we're entering from
     ! C code
@@ -228,6 +232,8 @@ IN: bootstrap.x86
 
 ! Contexts
 : jit-switch-context ( reg -- )
+    -8 jit-scrub-return
+
     ! Save ds, rs registers
     jit-save-context
 
index 58343a4eeef247ba507c07451b83da6fdc42792f..d3adcf3960c49f373d3303b00a2fab4872f406aa 100644 (file)
@@ -35,9 +35,6 @@ HOOK: reserved-stack-space cpu ( -- n )
 
 : spill@ ( n -- op ) spill-offset special-offset stack@ ;
 
-: gc-root-offsets ( seq -- seq' )
-    [ n>> spill-offset special-offset cell + ] map f like ;
-
 : decr-stack-reg ( n -- )
     dup 0 = [ drop ] [ stack-reg swap SUB ] if ;
 
@@ -483,8 +480,15 @@ M:: x86 %check-nursery-branch ( label size cc temp1 temp2 -- )
         { cc/<= [ label JG ] }
     } case ;
 
+M: x86 gc-root-offsets
+    [ n>> spill-offset special-offset cell + cell /i ] map f like ;
+
+M: x86 %call-gc ( gc-map -- )
+    \ minor-gc %call
+    gc-map-here ;
+
 M: x86 %alien-global ( dst symbol library -- )
-    [ 0 MOV ] 2dip rc-absolute-cell rel-dlsym ;    
+    [ 0 MOV ] 2dip rc-absolute-cell rel-dlsym ;
 
 M: x86 %epilogue ( n -- ) cell - incr-stack-reg ;
 
@@ -563,6 +567,20 @@ M:: x86 %compare-imm-branch ( label src1 src2 cc -- )
     src1 src2 (%compare-imm)
     label cc %branch ;
 
+M:: x86 %dispatch ( src temp -- )
+    ! Load jump table base.
+    temp HEX: ffffffff MOV
+    building get length :> start
+    0 rc-absolute-cell rel-here
+    ! Add jump table base
+    temp src HEX: 7f [++] JMP
+    building get length :> end
+    ! Fix up the displacement above
+    cell alignment
+    [ end start - + building get dup pop* push ]
+    [ (align-code) ]
+    bi ;
+
 M:: x86 %spill ( src rep dst -- )
     dst src rep %copy ;
 
@@ -591,8 +609,8 @@ M:: x86 %load-stack-param ( dst n rep -- )
 M:: x86 %local-allot ( dst size align offset -- )
     dst offset local-allot-offset special-offset stack@ LEA ;
 
-M: x86 %alien-indirect ( src -- )
-    ?spill-slot CALL ;
+M: x86 %alien-indirect ( src gc-map -- )
+    [ ?spill-slot CALL ] [ gc-map-here ] bi* ;
 
 M: x86 %loop-entry 16 alignment [ NOP ] times ;
 
index a41fc1e6c339be8c178d2592f1688c06dfff782f..d0977dd3d0ed3628934e12254e4a6535407e5717 100644 (file)
@@ -34,6 +34,10 @@ ARTICLE: "network-connection" "Connection-oriented networking"
     <client>
     with-client
 }
+"The local address of a client socket can be controlled with this word:"
+{ $subsections
+    with-local-address
+}
 "Connection-oriented network servers are implemented by first opening a server socket, then waiting for connections:"
 { $subsections
     <server>
@@ -215,3 +219,17 @@ HELP: send
 HELP: resolve-host
 { $values { "addrspec" "an address specifier" } { "seq" "a sequence of address specifiers" } }
 { $description "Resolves host names to IP addresses." } ;
+
+HELP: with-local-address
+{ $values { "addr" "an " { $link inet4 } " or " { $link inet6 } " address specifier" } { "quot" quotation } }
+{ $description "Client sockets opened within the scope of the quotation passed to this combinator will have their local address bound to the given address." }
+{ $examples
+  { "Binds the local address of a newly created client socket within the quotation to 127.0.0.1."
+    "This ensures that all traffic originates from the given address (the port is choosen by the TCP stack)." }
+  { $code "\"127.0.0.1\" 0 <inet4> [ ] with-local-address" }
+  $nl
+  { "Binds the local address of a newly created client socket within the quotation to the local address 192.168.0.1 and the local port 23000. "
+    "Be aware that you can only have one client socket with the same local address at a time or else an I/O error (\"address already in use\") will be thrown."
+  }
+  { $code "\"192.168.0.1\" 23000 <inet4> [ ] with-local-address" }
+} ;
index 3d21a3e7d60602864c8c69103b3f7929835df436..a2e9f4fa4813ea2b1900866bd68fa9ff7c38d8dd 100644 (file)
@@ -5,6 +5,8 @@ IN: math.primes.tests
 { 1237 } [ 1234 next-prime ] unit-test
 { f t } [ 1234 prime? 1237 prime? ] unit-test
 { { 2 3 5 7 } } [ 10 primes-upto >array ] unit-test
+{ { 2 } } [ 2 primes-upto >array ] unit-test
+{ { } } [ 1 primes-upto >array ] unit-test
 { { 999983 1000003 } } [ 999982 1000010 primes-between >array ] unit-test
 
 { { 4999963 4999999 5000011 5000077 5000081 } }
@@ -13,6 +15,12 @@ IN: math.primes.tests
 { { 8999981 8999993 9000011 9000041 } }
 [ 8999980 9000045 primes-between >array ] unit-test
 
+{ { } } [ 5 4 primes-between >array ] unit-test
+
+{ { 2 } } [ 2 2 primes-between >array ] unit-test
+
+{ { 2 } } [ 1.5 2.5 primes-between >array ] unit-test
+
 [ 2 ] [ 1 next-prime ] unit-test
 [ 3 ] [ 2 next-prime ] unit-test
 [ 5 ] [ 3 next-prime ] unit-test
index 81193af400bfa749003a2b01b831b5e9dfb059c3..7611e22b70cf60591e8a38d6af5ffd0a15062270 100644 (file)
@@ -46,11 +46,24 @@ PRIVATE>
         next-odd [ dup prime? ] [ 2 + ] until
     ] if ; foldable
 
-: primes-between ( low high -- seq )
+<PRIVATE
+
+: (primes-between) ( low high -- seq )
     [ [ 3 max dup even? [ 1 + ] when ] dip 2 <range> ]
     [ <primes-vector> ] 2bi
     [ '[ [ prime? ] _ push-if ] each ] keep clone ;
 
+PRIVATE>
+
+: primes-between ( low high -- seq )
+    [ ceiling >integer ] [ floor >integer ] bi*
+    {
+        { [ 2dup > ] [ 2drop V{ } clone ] }
+        { [ dup 2 = ] [ 2drop V{ 2 } clone ] }
+        { [ dup 2 < ] [ 2drop V{ } clone ] }
+        [ (primes-between) ]
+    } cond ;
+
 : primes-upto ( n -- seq ) 2 swap primes-between ;
 
 : coprime? ( a b -- ? ) gcd nip 1 = ; foldable
diff --git a/basis/math/vectors/simd/cords/cords-tests.factor b/basis/math/vectors/simd/cords/cords-tests.factor
new file mode 100644 (file)
index 0000000..eee11b3
--- /dev/null
@@ -0,0 +1,4 @@
+USING: math.vectors.simd math.vectors.simd.cords tools.test ;\r
+IN: math.vectors.simd.cords.tests\r
+\r
+[ float-4{ 1.0 2.0 3.0 4.0 } ] [ double-4{ 1.0 2.0 3.0 4.0 } >float-4 ] unit-test\r
index 4d98af538fd8229ae5281a150285168d59f8c2d2..cc3aa023e72119f2eeab49b3505c1662872ae613 100644 (file)
@@ -28,8 +28,8 @@ BOA-EFFECT [ N 2 * "n" <array> { "v" } <effect> ]
 WHERE
 
 : >A ( seq -- A )
-    [ N head >A/2 ]
-    [ N tail >A/2 ] bi cord-append ;
+    [ N head-slice >A/2 ]
+    [ N tail-slice >A/2 ] bi cord-append ;
 
 \ A-boa
 { N ndip A/2-boa cord-append } { A/2-boa } >quotation prefix >quotation
index e8a103d449941500612fb8029eeacad57d678018..df67703d5cf2aeba7e4892d79b5e89226d58c917 100644 (file)
@@ -1,3 +1,3 @@
 USING: math.vectors.simd mirrors ;
 IN: math.vectors.simd.mirrors
-INSTANCE: simd-128          enumerated-sequence
+INSTANCE: simd-128          inspected-sequence
index f12d34e1701bfb3005bc8d4f79bfa974d61ee0bf..819c3aa087f680fba1469434e12ca6dc701851d1 100644 (file)
@@ -48,14 +48,14 @@ M: mirror assoc-size object>> layout-of second ;
 
 INSTANCE: mirror assoc
 
-MIXIN: enumerated-sequence
-INSTANCE: array             enumerated-sequence
-INSTANCE: vector            enumerated-sequence
-INSTANCE: callable          enumerated-sequence
-INSTANCE: byte-array        enumerated-sequence
+MIXIN: inspected-sequence
+INSTANCE: array             inspected-sequence
+INSTANCE: vector            inspected-sequence
+INSTANCE: callable          inspected-sequence
+INSTANCE: byte-array        inspected-sequence
 
 GENERIC: make-mirror ( obj -- assoc )
 M: hashtable make-mirror ;
 M: integer make-mirror drop f ;
-M: enumerated-sequence make-mirror <enum> ;
+M: inspected-sequence make-mirror <enum> ;
 M: object make-mirror <mirror> ;
index 7d0cb4057673bb8346b33c7f7819c38a9ac3649a..201a1c28d23650f36530152143ca22817d67e4f3 100644 (file)
@@ -226,7 +226,9 @@ M: object pprint-object ( obj -- )
 M: object pprint* pprint-object ;
 M: vector pprint* pprint-object ;
 M: byte-vector pprint* pprint-object ;
-M: hashtable pprint* pprint-object ;
+M: hashtable pprint*
+    nesting-limit inc
+    [ pprint-object ] [ nesting-limit dec ] [ ] cleanup ;
 M: curry pprint* pprint-object ;
 M: compose pprint* pprint-object ;
 M: hash-set pprint* pprint-object ;
index 5be500abd4c1d4d7ece566a3dc730b269522bce7..766fbe87c0b0cf75a1c2143b8a48c8954420844f 100644 (file)
@@ -1,8 +1,8 @@
 ! Copyright (C) 2008, 2010 Slava Pestov, Joe Groff.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors assocs sequences sorting binary-search fry math
-math.order arrays classes combinators kernel functors math.functions
-math.vectors ;
+math.order arrays classes combinators kernel functors locals
+math.functions math.vectors ;
 IN: sequences.cords
 
 MIXIN: cord
@@ -47,57 +47,62 @@ M: T cord-append
     [ [ head>> ] dip call ]
     [ [ tail>> ] dip call ] 2bi cord-append ; inline
 
-: cord-2map ( cord cord quot -- cord' )
-    [ [ [ head>> ] bi@ ] dip call ]
-    [ [ [ tail>> ] bi@ ] dip call ] 3bi cord-append ; inline
+:: cord-2map ( cord-a cord-b quot fallback -- cord' )
+    cord-a cord-b 2dup [ cord? ] both? [
+        [ [ head>> ] bi@ quot call ]
+        [ [ tail>> ] bi@ quot call ] 2bi cord-append
+    ] [ fallback call ] if ; inline
 
 : cord-both ( cord quot -- h t )
     [ [ head>> ] [ tail>> ] bi ] dip bi@ ; inline
 
-: cord-2both ( cord cord quot -- h t )
-    [ [ [ head>> ] bi@ ] dip call ]
-    [ [ [ tail>> ] bi@ ] dip call ] 3bi ; inline
+:: cord-2both ( cord-a cord-b quot combine fallback -- result )
+    cord-a cord-b 2dup [ cord? ] both? [
+        [ [ head>> ] bi@ quot call ]
+        [ [ tail>> ] bi@ quot call ] 2bi combine call
+    ] [ fallback call ] if ; inline
 
 <PRIVATE
 : split-shuffle ( shuf -- sh uf )
     dup length 2 /i cut* ; foldable
 PRIVATE>
 
-M: cord v+                [ v+                ] cord-2map ; inline
-M: cord v-                [ v-                ] cord-2map ; inline
+M: cord v+                [ v+                ] [ call-next-method ] cord-2map ; inline
+M: cord v-                [ v-                ] [ call-next-method ] cord-2map ; inline
 M: cord vneg              [ vneg              ] cord-map  ; inline
-M: cord v+-               [ v+-               ] cord-2map ; inline
-M: cord vs+               [ vs+               ] cord-2map ; inline
-M: cord vs-               [ vs-               ] cord-2map ; inline
-M: cord vs*               [ vs*               ] cord-2map ; inline
-M: cord v*                [ v*                ] cord-2map ; inline
-M: cord v/                [ v/                ] cord-2map ; inline
-M: cord vmin              [ vmin              ] cord-2map ; inline
-M: cord vmax              [ vmax              ] cord-2map ; inline
-M: cord v.                [ v.                ] cord-2both + ; inline
+M: cord v+-               [ v+-               ] [ call-next-method ] cord-2map ; inline
+M: cord vs+               [ vs+               ] [ call-next-method ] cord-2map ; inline
+M: cord vs-               [ vs-               ] [ call-next-method ] cord-2map ; inline
+M: cord vs*               [ vs*               ] [ call-next-method ] cord-2map ; inline
+M: cord v*                [ v*                ] [ call-next-method ] cord-2map ; inline
+M: cord v/                [ v/                ] [ call-next-method ] cord-2map ; inline
+M: cord vmin              [ vmin              ] [ call-next-method ] cord-2map ; inline
+M: cord vmax              [ vmax              ] [ call-next-method ] cord-2map ; inline
+M: cord v.
+    [ v.                ] [ + ] [ call-next-method ] cord-2both ; inline
 M: cord vsqrt             [ vsqrt             ] cord-map  ; inline
 M: cord sum               [ sum               ] cord-both + ; inline
 M: cord vabs              [ vabs              ] cord-map  ; inline
-M: cord vbitand           [ vbitand           ] cord-2map ; inline
-M: cord vbitandn          [ vbitandn          ] cord-2map ; inline
-M: cord vbitor            [ vbitor            ] cord-2map ; inline
-M: cord vbitxor           [ vbitxor           ] cord-2map ; inline
+M: cord vbitand           [ vbitand           ] [ call-next-method ] cord-2map ; inline
+M: cord vbitandn          [ vbitandn          ] [ call-next-method ] cord-2map ; inline
+M: cord vbitor            [ vbitor            ] [ call-next-method ] cord-2map ; inline
+M: cord vbitxor           [ vbitxor           ] [ call-next-method ] cord-2map ; inline
 M: cord vbitnot           [ vbitnot           ] cord-map  ; inline
-M: cord vand              [ vand              ] cord-2map ; inline
-M: cord vandn             [ vandn             ] cord-2map ; inline
-M: cord vor               [ vor               ] cord-2map ; inline
-M: cord vxor              [ vxor              ] cord-2map ; inline
+M: cord vand              [ vand              ] [ call-next-method ] cord-2map ; inline
+M: cord vandn             [ vandn             ] [ call-next-method ] cord-2map ; inline
+M: cord vor               [ vor               ] [ call-next-method ] cord-2map ; inline
+M: cord vxor              [ vxor              ] [ call-next-method ] cord-2map ; inline
 M: cord vnot              [ vnot              ] cord-map  ; inline
 M: cord vlshift           '[ _ vlshift        ] cord-map  ; inline
 M: cord vrshift           '[ _ vrshift        ] cord-map  ; inline
 M: cord (vmerge-head)     [ head>> ] bi@ (vmerge) cord-append ; inline
 M: cord (vmerge-tail)     [ tail>> ] bi@ (vmerge) cord-append ; inline
-M: cord v<=               [ v<=               ] cord-2map ; inline
-M: cord v<                [ v<                ] cord-2map ; inline
-M: cord v=                [ v=                ] cord-2map ; inline
-M: cord v>                [ v>                ] cord-2map ; inline
-M: cord v>=               [ v>=               ] cord-2map ; inline
-M: cord vunordered?       [ vunordered?       ] cord-2map ; inline
+M: cord v<=               [ v<=               ] [ call-next-method ] cord-2map ; inline
+M: cord v<                [ v<                ] [ call-next-method ] cord-2map ; inline
+M: cord v=                [ v=                ] [ call-next-method ] cord-2map ; inline
+M: cord v>                [ v>                ] [ call-next-method ] cord-2map ; inline
+M: cord v>=               [ v>=               ] [ call-next-method ] cord-2map ; inline
+M: cord vunordered?       [ vunordered?       ] [ call-next-method ] cord-2map ; inline
 M: cord vany?             [ vany?             ] cord-both or  ; inline
 M: cord vall?             [ vall?             ] cord-both and ; inline
 M: cord vnone?            [ vnone?            ] cord-both and ; inline
index eea9e83b5832ab27fe0e11a38b68091baec5712b..17bed718fb8f0c99de33f9486a0eb9f444fe1f42 100644 (file)
@@ -3,4 +3,4 @@
 USING: mirrors specialized-arrays math.vectors ;
 IN: specialized-arrays.mirrors
 
-INSTANCE: specialized-array enumerated-sequence
+INSTANCE: specialized-array inspected-sequence
index 5fa88e39a22b0c718704dd7b64ab8d8802419829..9754fd2abcbab5dcb32a0440c31392ac68dff64f 100644 (file)
@@ -137,14 +137,16 @@ M: pointer underlying-type
         bi
     ] "" make ;
 
-PRIVATE>
-
-: direct-slice ( from to seq -- seq' )
-    check-slice
+: direct-slice-unsafe ( from to seq -- seq' )
     [ nip nth-c-ptr ]
     [ drop swap - ]
     [ 2nip ] 3tri direct-like ; inline
 
+PRIVATE>
+
+: direct-slice ( from to seq -- seq' )
+    check-slice direct-slice-unsafe ; inline
+
 : direct-head ( seq n -- seq' ) (head) direct-slice ; inline
 : direct-tail ( seq n -- seq' ) (tail) direct-slice ; inline
 : direct-head* ( seq n -- seq' ) from-end direct-head ; inline
diff --git a/basis/specialized-vectors/mirrors/authors.txt b/basis/specialized-vectors/mirrors/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/specialized-vectors/mirrors/mirrors.factor b/basis/specialized-vectors/mirrors/mirrors.factor
new file mode 100644 (file)
index 0000000..bb559a0
--- /dev/null
@@ -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
index f96aea6815a7fae21f98d7b614f2b7ed84833dc8..2b5b2f3f92e2827dbdc7cf2090abd211484a045a 100644 (file)
@@ -1,27 +1,30 @@
 ! Copyright (C) 2008, 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors alien alien.c-types alien.parser assocs
-compiler.units functors growable kernel lexer math namespaces
-parser prettyprint.custom sequences specialized-arrays
-specialized-arrays.private strings vocabs vocabs.parser
-vocabs.generated fry make ;
+classes compiler.units functors growable kernel lexer math
+namespaces parser prettyprint.custom sequences
+specialized-arrays specialized-arrays.private strings
+vocabs vocabs.loader vocabs.parser vocabs.generated fry make ;
 FROM: sequences.private => nth-unsafe ;
 FROM: specialized-arrays.private => nth-c-ptr direct-like ;
 QUALIFIED: vectors.functor
 IN: specialized-vectors
 
+MIXIN: specialized-vector
+
 <PRIVATE
 
 FUNCTOR: define-vector ( T -- )
 
-V   DEFINES-CLASS ${T}-vector
+V DEFINES-CLASS ${T}-vector
 
-A   IS      ${T}-array
-<A> IS      <${A}>
+A          IS ${T}-array
+>A         IS >${A}
+<A>        IS <${A}>
 <direct-A> IS <direct-${A}>
 
->V  DEFERS >${V}
-V{  DEFINES ${V}{
+>V DEFERS >${V}
+V{ DEFINES ${V}{
 
 WHERE
 
@@ -43,8 +46,14 @@ 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
 
+M: A like
+    drop dup A instance? [
+        dup V instance? [ [ >c-ptr ] [ length>> ] bi <direct-A> ] [ >A ] if
+    ] unless ; inline
+
 SYNTAX: V{ \ } [ >V ] parse-literal ;
 
+INSTANCE: V specialized-vector
 INSTANCE: V growable
 
 ;FUNCTOR
@@ -78,3 +87,5 @@ SYNTAX: SPECIALIZED-VECTOR:
     scan-c-type
     [ define-array-vocab use-vocab ]
     [ define-vector-vocab use-vocab ] bi ;
+
+{ "specialized-vectors" "mirrors" } "specialized-vectors.mirrors" require-when
index df3ef413650ee23edb290071ae650936f4d56800..522893f3687d6817440e6f7391a09e1f48b51e95 100644 (file)
@@ -2,8 +2,7 @@ IN: tools.disassembler.udis.tests
 USING: tools.disassembler.udis tools.test alien.c-types system combinators kernel ;
 
 {
-    { [ os linux? cpu x86.64? and ] [ [ 656 ] [ ud heap-size ] unit-test ] }
-    { [ os macosx? cpu x86.32? and ] [ [ 592 ] [ ud heap-size ] unit-test ] }
-    { [ os macosx? cpu x86.64? and ] [ [ 656 ] [ ud heap-size ] unit-test ] }
+    { [ cpu x86.32? ] [ [ 604 ] [ ud heap-size ] unit-test ] }
+    { [ cpu x86.64? ] [ [ 672 ] [ ud heap-size ] unit-test ] }
     [ ]
 } cond
\ No newline at end of file
index e998a5cfdb2af984fa3a327533b70e5e63ff9134..8cf885f5830db65f0c56120bdfaa5104b8f3df6a 100644 (file)
@@ -67,7 +67,11 @@ STRUCT: ud
     { c3 uchar }
     { inp_cache uchar[256] }
     { inp_sess uchar[64] }
-    { itab_entry void* } ;
+    { have_modrm uchar }
+    { modrm uchar }
+    { user_opaque_data void* }
+    { itab_entry void* }
+    { le void* } ;
 
 FUNCTION: void ud_translate_intel ( ud* u ) ;
 FUNCTION: void ud_translate_att ( ud* u ) ;
index 8a7ff5b7b2455594dad04de5a71ee78e50c2d45f..4bb8814e4cad00f26462966da331dc166d620108 100644 (file)
@@ -1,4 +1,5 @@
-USING: definitions kernel locals.definitions see see.private typed words ;
+USING: definitions kernel locals.definitions see see.private typed words
+summary make accessors classes ;
 IN: typed.prettyprint
 
 PREDICATE: typed-lambda-word < lambda-word "typed-word" word-prop ;
@@ -9,3 +10,24 @@ M: typed-lambda-word definer drop \ TYPED:: \ ; ;
 M: typed-word definition "typed-def" word-prop ;
 M: typed-word declarations. "typed-word" word-prop declarations. ;
 
+M: input-mismatch-error summary
+    [
+        "Typed word “" %
+        dup word>> name>> %
+        "” expected input value of type " %
+        dup expected-type>> name>> %
+        " but got " %
+        dup value>> class name>> %
+        drop
+    ] "" make ;
+
+M: output-mismatch-error summary
+    [
+        "Typed word “" %
+        dup word>> name>> %
+        "” expected to output value of type " %
+        dup expected-type>> name>> %
+        " but gave " %
+        dup value>> class name>> %
+        drop
+    ] "" make ;
index bca1136ee6bb57f44eefd378931a4d3526e5772e..70edcf2334c383fde7c868419b09f731312573d3 100644 (file)
@@ -1,6 +1,6 @@
 USING: accessors effects eval kernel layouts math namespaces
-quotations tools.test typed words words.symbol
-compiler.tree.debugger prettyprint definitions compiler.units ;
+quotations tools.test typed words words.symbol combinators.short-circuit
+compiler.tree.debugger prettyprint definitions compiler.units sequences ;
 IN: typed.tests
 
 TYPED: f+ ( a: float b: float -- c: float )
@@ -24,14 +24,17 @@ TYPED: dee ( x: tweedle-dee -- y )
 TYPED: dum ( x: tweedle-dum -- y )
     drop \ tweedle-dum ;
 
-[ \ tweedle-dum new dee ] [ input-mismatch-error? ] must-fail-with
-[ \ tweedle-dee new dum ] [ input-mismatch-error? ] must-fail-with
+[ \ tweedle-dum new dee ]
+[ { [ input-mismatch-error? ] [ expected-type>> tweedle-dee = ] [ value>> tweedle-dum? ] } 1&& ] must-fail-with
 
+[ \ tweedle-dee new dum ]
+[ { [ input-mismatch-error? ] [ expected-type>> tweedle-dum = ] [ value>> tweedle-dee? ] } 1&& ] must-fail-with
 
 TYPED: dumdum ( x -- y: tweedle-dum )
     drop \ tweedle-dee new ;
 
-[ f dumdum ] [ output-mismatch-error? ] must-fail-with
+[ f dumdum ]
+[ { [ output-mismatch-error? ] [ expected-type>> tweedle-dum = ] [ value>> tweedle-dee? ] } 1&& ] must-fail-with
 
 TYPED:: f+locals ( a: float b: float -- c: float )
     a b + ;
index 50da7b1bad5e1386c45c563058ad97cb44837662..fe2ba417220650e9179f494e64005a6a8073092b 100644 (file)
@@ -7,7 +7,7 @@ locals.parser macros stack-checker.dependencies ;
 FROM: classes.tuple.private => tuple-layout ;
 IN: typed
 
-ERROR: type-mismatch-error word expected-types ;
+ERROR: type-mismatch-error value expected-type word expected-types ;
 ERROR: input-mismatch-error < type-mismatch-error ;
 ERROR: output-mismatch-error < type-mismatch-error ;
 
@@ -28,9 +28,6 @@ PREDICATE: typed-word < word "typed-word" word-prop >boolean ;
 : typed-stack-effect? ( effect -- ? )
     [ object = ] all? not ;
 
-: input-mismatch-quot ( word types -- quot )
-    [ input-mismatch-error ] 2curry ;
-
 : depends-on-unboxing ( class -- )
     [ dup tuple-layout depends-on-tuple-layout ]
     [ depends-on-final ]
@@ -47,7 +44,7 @@ PREDICATE: typed-word < word "typed-word" word-prop >boolean ;
 
 :: unboxer ( error-quot word types type -- quot )
     type "coercer" word-prop [ ] or
-    [ dup type instance? [ word types error-quot call ] unless ]
+    type type word types error-quot '[ dup _ instance? [ _ _ _ @ ] unless ]
     type (unboxer)
     compose compose ;
 
index e6e49d852b4118e9fb01abb478e6974fa9d1d34f..4bb95e254179da8c99ab85de844f12e2e3302437 100644 (file)
@@ -17,7 +17,8 @@ else
     if Err.Number = 0 then\r
         if http.Status = 200 then\r
             dim dest_stream\r
-            set dest_stream = CreateObject("ADODB.Stream")\r
+            odd = "DOD"\r
+            set dest_stream = CreateObject("A"+odd+"B"+".Stream")\r
 \r
             Err.Clear\r
             dest_stream.Type = 1 ' adTypeBinary\r
index 423abbc277b4d6159497fdea711aba54f888eaaa..d3736db9bfce8c85b143df07f67bdbecb35de5a5 100755 (executable)
@@ -11,7 +11,7 @@ $nl
 $nl
 "The second way is to create a configuration file. You can list additional vocabulary roots in a file that Factor reads at startup:"
 { $subsections "factor-roots" }
-"Finally, you can add vocabulary roots dynamically using a word:"
+"Finally, you can add vocabulary roots by calling a word from your " { $snippet "factor-rc" } " file (see " { $link "factor-rc" } "):"
 { $subsections add-vocab-root } ;
 
 ARTICLE: "vocabs.roots" "Vocabulary roots"
diff --git a/extra/alien/handles/authors.txt b/extra/alien/handles/authors.txt
new file mode 100644 (file)
index 0000000..f13c9c1
--- /dev/null
@@ -0,0 +1 @@
+Joe Groff
diff --git a/extra/alien/handles/handles-tests.factor b/extra/alien/handles/handles-tests.factor
new file mode 100644 (file)
index 0000000..38ce7c2
--- /dev/null
@@ -0,0 +1,45 @@
+! (c)2010 Joe Groff bsd license
+USING: accessors alien alien.c-types alien.handles alien.syntax
+destructors kernel math tools.test ;
+IN: alien.handles.tests
+
+TUPLE: thingy { x integer } ;
+C: <thingy> thingy
+
+CALLBACK: int thingy-callback ( uint thingy-handle ) ;
+CALLBACK: int thingy-ptr-callback ( void* thingy-handle ) ;
+
+: test-thingy-callback ( -- alien )
+    [ alien-handle> x>> 1 + ] thingy-callback ;
+
+: test-thingy-ptr-callback ( -- alien )
+    [ alien-handle-ptr> x>> 1 + ] thingy-ptr-callback ;
+
+: invoke-test-thingy-callback ( thingy -- n )
+    test-thingy-callback int { uint } cdecl alien-indirect ;
+: invoke-test-thingy-ptr-callback ( thingy -- n )
+    test-thingy-ptr-callback int { void* } cdecl alien-indirect ;
+
+[ t f ] [
+    [ 5 <thingy> <alien-handle> &release-alien-handle [ alien-handle? ] keep ] with-destructors
+    alien-handle?
+] unit-test
+
+[ t f ] [
+    [ 5 <thingy> <alien-handle-ptr> &release-alien-handle-ptr [ alien-handle-ptr? ] keep ] with-destructors
+    alien-handle-ptr?
+] unit-test
+
+[ 6 ] [
+    [
+        5 <thingy> <alien-handle> &release-alien-handle
+        invoke-test-thingy-callback
+    ] with-destructors
+] unit-test
+
+[ 6 ] [
+    [
+        5 <thingy> <alien-handle-ptr> &release-alien-handle-ptr
+        invoke-test-thingy-ptr-callback
+    ] with-destructors
+] unit-test
diff --git a/extra/alien/handles/handles.factor b/extra/alien/handles/handles.factor
new file mode 100644 (file)
index 0000000..e1b5a71
--- /dev/null
@@ -0,0 +1,49 @@
+! (c)2010 Joe Groff bsd license
+USING: alien alien.destructors assocs kernel math math.bitwise
+namespaces ;
+IN: alien.handles
+
+<PRIVATE
+
+SYMBOLS: alien-handle-counter alien-handles ;
+
+alien-handle-counter [ 0 ] initialize
+alien-handles [ H{ } clone ] initialize
+
+: biggest-handle ( -- n )
+    -1 32 bits ; inline
+
+: (next-handle) ( -- n )
+    alien-handle-counter [ 1 + biggest-handle bitand dup ] change-global ; inline
+
+: next-handle ( -- n )
+    [ (next-handle) dup alien-handles get-global key? ] [ drop ] while ;
+
+PRIVATE>
+
+: <alien-handle> ( object -- int )
+    next-handle [ alien-handles get-global set-at ] keep ; inline
+: alien-handle> ( int -- object )
+    alien-handles get-global at ; inline
+
+: alien-handle? ( int -- ? )
+    alien-handles get-global key? >boolean ; inline
+
+: release-alien-handle ( int -- )
+    alien-handles get-global delete-at ; inline
+
+DESTRUCTOR: release-alien-handle
+
+: <alien-handle-ptr> ( object -- void* )
+    <alien-handle> <alien> ; inline
+: alien-handle-ptr> ( void* -- object )
+    alien-address alien-handle> ; inline
+
+: alien-handle-ptr? ( alien -- ? )
+    alien-address alien-handle? ; inline
+
+: release-alien-handle-ptr ( alien -- )
+    alien-address release-alien-handle ; inline
+
+DESTRUCTOR: release-alien-handle-ptr
+
diff --git a/extra/alien/handles/summary.txt b/extra/alien/handles/summary.txt
new file mode 100644 (file)
index 0000000..17c2a24
--- /dev/null
@@ -0,0 +1 @@
+Generate integer handle values to allow Factor object references to be passed through the FFI
index 570f84d1b9b30723d97e28f927756949cc8425e7..c0d560a2e16ab3f7ff1ae5699502a1f461cf57aa 100644 (file)
@@ -1,5 +1,8 @@
 ! (c)2010 Joe Groff bsd license\r
-USING: byte-arrays.hex io.encodings.8-bit.koi8-r io.encodings.detect tools.test ;\r
+USING: byte-arrays byte-arrays.hex io.encodings.8-bit.koi8-r\r
+io.encodings.8-bit.latin1 io.encodings.binary\r
+io.encodings.detect io.encodings.utf16 io.encodings.utf32\r
+io.encodings.utf8 namespaces tools.test ;\r
 IN: io.encodings.detect.tests\r
 \r
 ! UTF encodings with BOMs\r
@@ -27,6 +30,7 @@ unit-test
 unit-test\r
 \r
 ! Default to utf8 if decoding succeeds and there are no nulls\r
+[ utf8 ] [ HEX{ } detect-byte-array ] unit-test\r
 [ utf8 ] [ HEX{ 31 32 33 } detect-byte-array ] unit-test\r
 [ utf8 ] [ HEX{ 31 32 C2 A0 33 } detect-byte-array ] unit-test\r
 [ latin1 ] [ HEX{ 31 32 A0 33 } detect-byte-array ] unit-test\r
@@ -38,3 +42,4 @@ unit-test
 \r
 [ binary ] [ HEX{ 31 32 33 C2 A0 00 } detect-byte-array ] unit-test\r
 [ binary ] [ HEX{ 31 32 33 C2 A0 00 30 } detect-byte-array ] unit-test\r
+\r
index a803c54c53ab22af6753d21d069ec9fa681c4e92..c8b01757f8ddb056f8acc1bd69a81c8707d24eba 100644 (file)
@@ -38,6 +38,7 @@ PRIVATE>
         { [ dup HEX{ EF BB BF } head? ] [ drop utf8 ] }\r
         { [ dup $[ "<?xml" >byte-array ] head? ] [ detect-xml-prolog ] }\r
         { [ 0 over member? ] [ drop binary ] }\r
+        { [ dup empty? ] [ drop utf8 ] }\r
         { [ dup valid-utf8? ] [ drop utf8 ] }\r
         [ drop default-8bit-encoding get ]\r
     } cond ;\r
index 856740d22956cad3d5c2ce5c49d53c37c236a466..678e780e6046728a5fb581fb85317131071721c4 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2005 Alex Chapman.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: alien alien.c-types alien.libraries alien.syntax kernel
-sequences words system combinators opengl.gl ;
+sequences words system combinators opengl.gl alien.destructors ;
 IN: opengl.glu
 
 <<
@@ -267,5 +267,21 @@ FUNCTION: GLint gluUnProject ( GLdouble winX, GLdouble winY, GLdouble winZ, GLdo
 ! FUNCTION: GLboolean gluCheckExtension ( GLubyte* extName, GLubyte* extString ) ;
 ! FUNCTION: GLint gluUnProject4 ( GLdouble winX, GLdouble winY, GLdouble winZ, GLdouble clipW, GLdouble* model, GLdouble* proj, GLint* view, GLdouble nearVal, GLdouble farVal, GLdouble* objX, GLdouble* objY, GLdouble* objZ, GLdouble* objW ) ;
 
+DESTRUCTOR: gluDeleteNurbsRenderer
+DESTRUCTOR: gluDeleteQuadric
+DESTRUCTOR: gluDeleteTess
+
+CALLBACK: void GLUtessBeginCallback ( GLenum type ) ;
+CALLBACK: void GLUtessBeginDataCallback ( GLenum type, void* data ) ;
+CALLBACK: void GLUtessEdgeFlagCallback ( GLboolean flag ) ;
+CALLBACK: void GLUtessEdgeFlagDataCallback ( GLboolean flag, void* data ) ;
+CALLBACK: void GLUtessVertexCallback ( void* vertex_data ) ;
+CALLBACK: void GLUtessVertexDataCallback ( void* vertex_data, void* data ) ;
+CALLBACK: void GLUtessEndCallback ( ) ;
+CALLBACK: void GLUtessEndDataCallback ( void* data ) ;
+CALLBACK: void GLUtessCombineDataCallback ( GLdouble* coords, void** vertex_data, GLfloat* weight, void** out_data, void* data ) ;
+CALLBACK: void GLUtessErrorCallback ( GLenum errno ) ;
+CALLBACK: void GLUtessErrorDataCallback ( GLenum errno, void* data ) ;
+
 : gl-look-at ( eye focus up -- )
     [ first3 ] tri@ gluLookAt ;
index 8efc07ceee07821a13a31b58a0370b016f3776ef..10c5024d588c766b8c5a3a47647e0ce1441524d9 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2009 Elie Chaftari.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: concurrency.promises namespaces kernel pop3 pop3.server
-sequences tools.test accessors ;
+sequences tools.test accessors calendar ;
 IN: pop3.tests
 
 FROM: pop3 => count delete ;
@@ -12,7 +12,7 @@ FROM: pop3 => count delete ;
 [ ] [
         <pop3-account>
             "127.0.0.1" >>host
-            "p1" get ?promise >>port
+            "p1" get 5 seconds ?promise-timeout >>port
         connect
 ] unit-test
 [ ] [ "username@host.com" >user ] unit-test
@@ -59,7 +59,7 @@ FROM: pop3 => count delete ;
 [ ] [
         <pop3-account>
             "127.0.0.1" >>host
-            "p2" get ?promise >>port
+            "p2" get 5 seconds ?promise-timeout >>port
             "username@host.com" >>user
             "password" >>pwd
         connect
index 8d3990fcd8efddbfbe02ee98aee82235f327a84b..d54b0cd337972cfd09f955e1e6f90373e24c0032 100644 (file)
@@ -59,6 +59,7 @@
   (ratio constant  "ratios")
   (declaration keyword "declaration words")
   (ebnf-form constant "EBNF: ... ;EBNF form")
+  (error-form warning "ERROR: ... ; form")
   (parsing-word keyword  "parsing words")
   (postpone-body comment "postponed form")
   (setter-word function-name "setter words (>>foo)")
     (,fuel-syntax--brace-words-regex 1 'factor-font-lock-parsing-word)
     (,fuel-syntax--alien-function-regex (1 'factor-font-lock-type-name)
                                         (2 'factor-font-lock-word))
+    (,fuel-syntax--alien-function-alias-regex (1 'factor-font-lock-word)
+                                              (2 'factor-font-lock-type-name)
+                                              (3 'factor-font-lock-word))
     (,fuel-syntax--alien-callback-regex (1 'factor-font-lock-type-name)
                                         (2 'factor-font-lock-word))
     (,fuel-syntax--vocab-ref-regexp  2 'factor-font-lock-vocabulary-name)
     (,fuel-syntax--typedef-regex (1 'factor-font-lock-type-name)
                                  (2 'factor-font-lock-type-name)
                                  (3 'factor-font-lock-invalid-syntax nil t))
+    (,fuel-syntax--c-global-regex (1 'factor-font-lock-type-name)
+                                  (2 'factor-font-lock-word)
+                                  (3 'factor-font-lock-invalid-syntax nil t))
+    (,fuel-syntax--c-type-regex (1 'factor-font-lock-type-name)
+                                (2 'factor-font-lock-invalid-syntax nil t))
     (,fuel-syntax--rename-regex (1 'factor-font-lock-word)
                                 (2 'factor-font-lock-vocabulary-name)
                                 (3 'factor-font-lock-word)
     (,fuel-syntax--float-regex . 'factor-font-lock-number)
     (,fuel-syntax--ratio-regex . 'factor-font-lock-ratio)
     (,fuel-syntax--type-definition-regex 2 'factor-font-lock-type-name)
+    (,fuel-syntax--error-regex 2 'factor-font-lock-error-form)
     (,fuel-syntax--method-definition-regex (1 'factor-font-lock-type-name)
                                            (2 'factor-font-lock-word))
     (,fuel-syntax--before-definition-regex (1 'factor-font-lock-type-name)
index 80010235b1c1c6dcffd826ff3e1eb4ca97f75ad7..e2db30db3d0b1a5487d2477deb9e679541054643 100644 (file)
   '(":" "::" ";" "&:" "<<" "<PRIVATE" ">>"\r
     "ABOUT:" "AFTER:" "ALIAS:" "ALIEN:" "ARTICLE:"\r
     "B" "BEFORE:" "BIN:"\r
-    "C:" "CALLBACK:" "ENUM:" "C-TYPE:" "CHAR:" "COM-INTERFACE:" "CONSTANT:" "CONSULT:" "call-next-method"\r
-    "DEFER:"\r
-    "EBNF:" ";EBNF" "ERROR:" "EXCLUDE:"\r
-    "f" "FORGET:" "FROM:" "FUNCTION:"\r
+    "C:" "CALLBACK:" "C-GLOBAL:" "C-TYPE:" "CHAR:" "COM-INTERFACE:" "CONSTANT:" "CONSULT:" "call-next-method"\r
+    "DEFER:" "DESTRUCTOR:"\r
+    "EBNF:" ";EBNF" "ENUM:" "ERROR:" "EXCLUDE:"\r
+    "f" "FORGET:" "FROM:" "FUNCTION:" "FUNCTION-ALIAS:"\r
     "GAME:" "GENERIC#" "GENERIC:"\r
     "GLSL-SHADER:" "GLSL-PROGRAM:"\r
     "HELP:" "HEX:" "HOOK:"\r
   (fuel-syntax--second-word-regex\r
    '("C-STRUCT:" "C-UNION:" "COM-INTERFACE:" "MIXIN:" "TUPLE:" "SINGLETON:" "SPECIALIZED-ARRAY:" "STRUCT:" "UNION:" "UNION-STRUCT:")))\r
 \r
+(defconst fuel-syntax--error-regex\r
+  (fuel-syntax--second-word-regex '("ERROR:")))\r
+\r
 (defconst fuel-syntax--tuple-decl-regex\r
   "^TUPLE: +\\([^ \n]+\\) +< +\\([^ \n]+\\)\\_>")\r
 \r
 (defconst fuel-syntax--sub-vocab-regex "^<\\([^ \n]+\\) *$")\r
 \r
 (defconst fuel-syntax--alien-function-regex\r
-  "\\_<FUNCTION: \\(\\w+\\) \\(\\w+\\)")\r
+  "\\_<FUNCTION: +\\(\\w+\\)[\n ]+\\(\\w+\\)")\r
+\r
+(defconst fuel-syntax--alien-function-alias-regex\r
+  "\\_<FUNCTION-ALIAS: +\\(\\w+\\)[\n ]+\\(\\w+\\)[\n ]+\\(\\w+\\)")\r
 \r
 (defconst fuel-syntax--alien-callback-regex\r
-  "\\_<CALLBACK: \\(\\w+\\) \\(\\w+\\)")\r
+  "\\_<CALLBACK: +\\(\\w+\\) +\\(\\w+\\)")\r
 \r
 (defconst fuel-syntax--indent-def-starts '("" ":"\r
                                            "AFTER" "BEFORE"\r
-                                           "ENUM" "COM-INTERFACE" "CONSULT"\r
-                                           "FROM" "FUNCTION:"\r
+                                           "COM-INTERFACE" "CONSULT"\r
+                                           "ENUM" "ERROR"\r
+                                           "FROM" "FUNCTION:" "FUNCTION-ALIAS:"\r
                                            "INTERSECTION:"\r
                                            "M" "M:" "MACRO" "MACRO:"\r
                                            "MEMO" "MEMO:" "METHOD"\r
 (defconst fuel-syntax--single-liner-regex\r
   (regexp-opt '("ABOUT:"\r
                 "ALIAS:"\r
-                "CONSTANT:" "C:" "C-TYPE:"\r
-                "DEFER:"\r
+                "CONSTANT:" "C:" "C-GLOBAL:" "C-TYPE:"\r
+                "DEFER:" "DESTRUCTOR:"\r
                 "FORGET:"\r
-                "GAME:" "GENERIC:" "GENERIC#" "GLSL-PROGRAM:" \r
+                "GAME:" "GENERIC:" "GENERIC#" "GLSL-PROGRAM:"\r
                 "HEX:" "HOOK:"\r
                 "IN:" "INSTANCE:"\r
                 "LIBRARY:"\r
 (defconst fuel-syntax--typedef-regex\r
   "\\_<TYPEDEF: +\\(\\w+\\) +\\(\\w+\\)\\( .*\\)?$")\r
 \r
+(defconst fuel-syntax--c-global-regex\r
+  "\\_<C-GLOBAL: +\\(\\w+\\) +\\(\\w+\\)\\( .*\\)?$")\r
+\r
+(defconst fuel-syntax--c-type-regex\r
+  "\\_<C-TYPE: +\\(\\w+\\)\\( .*\\)?$")\r
+\r
 (defconst fuel-syntax--rename-regex\r
   "\\_<RENAME: +\\(\\w+\\) +\\(\\w+\\) +=> +\\(\\w+\\)\\( .*\\)?$")\r
 \r
index 162d9272c6ca9a93a2941fdfcaa7087082519478..ddff576befd3814290e8f574d37add9b64a87109 100755 (executable)
@@ -60,4 +60,11 @@ inline cell popcount(cell x)
        return x;
 }
 
+inline bool bitmap_p(u8 *bitmap, cell index)
+{
+       cell byte = index >> 3;
+       cell bit = index & 7;
+       return (bitmap[byte] & (1 << bit)) != 0;
+}
+
 }
index d59563d81c448d82b434819fc8f52808c5d0c385..fb1b44c91e95f658e9d19f2b73641ff02057a82b 100644 (file)
@@ -35,16 +35,18 @@ void factor_vm::primitive_resize_byte_array()
        ctx->push(tag<byte_array>(reallot_array(array.untagged(),capacity)));
 }
 
-void growable_byte_array::append_bytes(void *elts, cell len)
+void growable_byte_array::grow_bytes(cell len)
 {
-       cell new_size = count + len;
-       factor_vm *parent = elements.parent;
-       if(new_size >= array_capacity(elements.untagged()))
-               elements = parent->reallot_array(elements.untagged(),new_size * 2);
-
-       memcpy(&elements->data<u8>()[count],elts,len);
-
        count += len;
+       if(count >= array_capacity(elements.untagged()))
+               elements = elements.parent->reallot_array(elements.untagged(),count * 2);
+}
+
+void growable_byte_array::append_bytes(void *elts, cell len)
+{
+       cell old_count = count;
+       grow_bytes(len);
+       memcpy(&elements->data<u8>()[old_count],elts,len);
 }
 
 void growable_byte_array::append_byte_array(cell byte_array_)
index 2da036709f6cf46e8c21a65ffddb28f7d3852378..f0faac248c8047fe15799dc085b68aec5ca5197e 100755 (executable)
@@ -7,6 +7,7 @@ struct growable_byte_array {
 
        explicit growable_byte_array(factor_vm *parent,cell capacity = 40) : count(0), elements(parent->allot_byte_array(capacity),parent) { }
 
+       void grow_bytes(cell len);
        void append_bytes(void *elts, cell len);
        void append_byte_array(cell elts);
 
index bb716cbc6dd3ad7bb9465eb588b07329a74843ca..64c17d8661ccd2e3d033d7fbfa23ed8455530028 100755 (executable)
@@ -108,7 +108,25 @@ stack_frame *factor_vm::frame_successor(stack_frame *frame)
        return (stack_frame *)((cell)frame - frame->size);
 }
 
-/* Allocates memory */
+cell factor_vm::frame_offset(stack_frame *frame)
+{
+       char *entry_point = (char *)frame_code(frame)->entry_point();
+       char *return_address = (char *)FRAME_RETURN_ADDRESS(frame,this);
+       if(return_address)
+               return return_address - entry_point;
+       else
+               return (cell)-1;
+}
+
+void factor_vm::set_frame_offset(stack_frame *frame, cell offset)
+{
+       char *entry_point = (char *)frame_code(frame)->entry_point();
+       if(offset == (cell)-1)
+               FRAME_RETURN_ADDRESS(frame,this) = NULL;
+       else
+               FRAME_RETURN_ADDRESS(frame,this) = entry_point + offset;
+}
+
 cell factor_vm::frame_scan(stack_frame *frame)
 {
        switch(frame_type(frame))
@@ -120,13 +138,7 @@ cell factor_vm::frame_scan(stack_frame *frame)
                                obj = obj.as<word>()->def;
 
                        if(obj.type_p(QUOTATION_TYPE))
-                       {
-                               char *return_addr = (char *)FRAME_RETURN_ADDRESS(frame,this);
-                               char *quot_entry_point = (char *)frame_code(frame)->entry_point();
-
-                               return tag_fixnum(quot_code_offset_to_scan(
-                                       obj.value(),(cell)(return_addr - quot_entry_point)));
-                       }    
+                               return tag_fixnum(quot_code_offset_to_scan(obj.value(),frame_offset(frame)));
                        else
                                return false_object;
                }
@@ -138,9 +150,6 @@ cell factor_vm::frame_scan(stack_frame *frame)
        }
 }
 
-namespace
-{
-
 struct stack_frame_accumulator {
        factor_vm *parent;
        growable_array frames;
@@ -159,8 +168,6 @@ struct stack_frame_accumulator {
        }
 };
 
-}
-
 void factor_vm::primitive_callstack_to_array()
 {
        data_root<callstack> callstack(ctx->pop(),this);
@@ -209,9 +216,9 @@ void factor_vm::primitive_set_innermost_stack_frame_quot()
        jit_compile_quot(quot.value(),true);
 
        stack_frame *inner = innermost_stack_frame(callstack.untagged());
-       cell offset = (char *)FRAME_RETURN_ADDRESS(inner,this) - (char *)inner->entry_point;
+       cell offset = frame_offset(inner);
        inner->entry_point = quot->entry_point;
-       FRAME_RETURN_ADDRESS(inner,this) = (char *)quot->entry_point + offset;
+       set_frame_offset(inner,offset);
 }
 
 void factor_vm::primitive_callstack_bounds()
index deaa41e4b8ef7b282ffdae7b1cabefab41c1fcaa..8b48d3672f8f38a142fcefaed54e606bd5eac72e 100644 (file)
@@ -12,12 +12,12 @@ Iteration is driven by visit_*() methods. Some of them define GC roots:
 - visit_context_code_blocks()
 - visit_callback_code_blocks() */
  
-template<typename Visitor> struct code_block_visitor {
+template<typename Fixup> struct code_block_visitor {
        factor_vm *parent;
-       Visitor visitor;
+       Fixup fixup;
 
-       explicit code_block_visitor(factor_vm *parent_, Visitor visitor_) :
-               parent(parent_), visitor(visitor_) {}
+       explicit code_block_visitor(factor_vm *parent_, Fixup fixup_) :
+               parent(parent_), fixup(fixup_) {}
 
        code_block *visit_code_block(code_block *compiled);
        void visit_object_code_block(object *obj);
@@ -26,33 +26,31 @@ template<typename Visitor> struct code_block_visitor {
        void visit_uninitialized_code_blocks();
 };
 
-template<typename Visitor>
-code_block *code_block_visitor<Visitor>::visit_code_block(code_block *compiled)
+template<typename Fixup>
+code_block *code_block_visitor<Fixup>::visit_code_block(code_block *compiled)
 {
-       return visitor(compiled);
+       return fixup.fixup_code(compiled);
 }
 
-template<typename Visitor>
+template<typename Fixup>
 struct call_frame_code_block_visitor {
        factor_vm *parent;
-       Visitor visitor;
+       Fixup fixup;
 
-       explicit call_frame_code_block_visitor(factor_vm *parent_, Visitor visitor_) :
-               parent(parent_), visitor(visitor_) {}
+       explicit call_frame_code_block_visitor(factor_vm *parent_, Fixup fixup_) :
+               parent(parent_), fixup(fixup_) {}
 
        void operator()(stack_frame *frame)
        {
-               cell offset = (cell)FRAME_RETURN_ADDRESS(frame,parent) - (cell)frame->entry_point;
-
-               code_block *new_block = visitor(parent->frame_code(frame));
-               frame->entry_point = new_block->entry_point();
-
-               FRAME_RETURN_ADDRESS(frame,parent) = (void *)((cell)frame->entry_point + offset);
+               cell offset = parent->frame_offset(frame);
+               code_block *compiled = fixup.fixup_code(parent->frame_code(frame));
+               frame->entry_point = compiled->entry_point();
+               parent->set_frame_offset(frame,offset);
        }
 };
 
-template<typename Visitor>
-void code_block_visitor<Visitor>::visit_object_code_block(object *obj)
+template<typename Fixup>
+void code_block_visitor<Fixup>::visit_object_code_block(object *obj)
 {
        switch(obj->type())
        {
@@ -60,9 +58,9 @@ void code_block_visitor<Visitor>::visit_object_code_block(object *obj)
                {
                        word *w = (word *)obj;
                        if(w->code)
-                               w->code = visitor(w->code);
+                               w->code = visit_code_block(w->code);
                        if(w->profiling)
-                               w->profiling = visitor(w->profiling);
+                               w->profiling = visit_code_block(w->profiling);
 
                        parent->update_word_entry_point(w);
                        break;
@@ -71,24 +69,24 @@ void code_block_visitor<Visitor>::visit_object_code_block(object *obj)
                {
                        quotation *q = (quotation *)obj;
                        if(q->code)
-                               parent->set_quot_entry_point(q,visitor(q->code));
+                               parent->set_quot_entry_point(q,visit_code_block(q->code));
                        break;
                }
        case CALLSTACK_TYPE:
                {
                        callstack *stack = (callstack *)obj;
-                       call_frame_code_block_visitor<Visitor> call_frame_visitor(parent,visitor);
+                       call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
                        parent->iterate_callstack_object(stack,call_frame_visitor);
                        break;
                }
        }
 }
 
-template<typename Visitor>
+template<typename Fixup>
 struct embedded_code_pointers_visitor {
-       Visitor visitor;
+       Fixup fixup;
 
-       explicit embedded_code_pointers_visitor(Visitor visitor_) : visitor(visitor_) {}
+       explicit embedded_code_pointers_visitor(Fixup fixup_) : fixup(fixup_) {}
 
        void operator()(instruction_operand op)
        {
@@ -96,29 +94,29 @@ struct embedded_code_pointers_visitor {
                if(type == RT_ENTRY_POINT
                        || type == RT_ENTRY_POINT_PIC
                        || type == RT_ENTRY_POINT_PIC_TAIL)
-                       op.store_code_block(visitor(op.load_code_block()));
+                       op.store_code_block(fixup.fixup_code(op.load_code_block()));
        }
 };
 
-template<typename Visitor>
-void code_block_visitor<Visitor>::visit_embedded_code_pointers(code_block *compiled)
+template<typename Fixup>
+void code_block_visitor<Fixup>::visit_embedded_code_pointers(code_block *compiled)
 {
        if(!parent->code->uninitialized_p(compiled))
        {
-               embedded_code_pointers_visitor<Visitor> visitor(this->visitor);
-               compiled->each_instruction_operand(visitor);
+               embedded_code_pointers_visitor<Fixup> operand_visitor(fixup);
+               compiled->each_instruction_operand(operand_visitor);
        }
 }
 
-template<typename Visitor>
-void code_block_visitor<Visitor>::visit_context_code_blocks()
+template<typename Fixup>
+void code_block_visitor<Fixup>::visit_context_code_blocks()
 {
-       call_frame_code_block_visitor<Visitor> call_frame_visitor(parent,visitor);
+       call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
        parent->iterate_active_callstacks(call_frame_visitor);
 }
 
-template<typename Visitor>
-void code_block_visitor<Visitor>::visit_uninitialized_code_blocks()
+template<typename Fixup>
+void code_block_visitor<Fixup>::visit_uninitialized_code_blocks()
 {
        std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks;
        std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin();
@@ -128,7 +126,7 @@ void code_block_visitor<Visitor>::visit_uninitialized_code_blocks()
        for(; iter != end; iter++)
        {
                new_uninitialized_blocks.insert(std::make_pair(
-                       visitor(iter->first),
+                       fixup.fixup_code(iter->first),
                        iter->second));
        }
 
index baf763357c5911f379c928160d708ab10141dd06..f20e2da37292d5c6a5a8c1dd12cbb16d03d19f69 100644 (file)
@@ -43,11 +43,22 @@ struct code_block
                return size;
        }
 
+       template<typename Fixup> cell size(Fixup fixup) const
+       {
+               return size();
+       }
+
        void *entry_point() const
        {
                return (void *)(this + 1);
        }
 
+       /* GC info is stored at the end of the block */
+       gc_info *block_gc_info() const
+       {
+               return (gc_info *)((u8 *)this + size() - sizeof(gc_info));
+       }
+
        void flush_icache()
        {
                factor::flush_icache((cell)this,size());
index 0b8b473e8b3704fd10c5487e1e09c6c551bdfba9..4a9eec59675529a50e3bd6b9b328f1f93ea7b9a3 100644 (file)
@@ -3,15 +3,17 @@ namespace factor
 
 struct must_start_gc_again {};
 
-template<typename TargetGeneration, typename Policy> struct data_workhorse {
+template<typename TargetGeneration, typename Policy> struct gc_workhorse : no_fixup {
        factor_vm *parent;
        TargetGeneration *target;
        Policy policy;
+       code_heap *code;
 
-       explicit data_workhorse(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
+       explicit gc_workhorse(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
                parent(parent_),
                target(target_),
-               policy(policy_) {}
+               policy(policy_),
+               code(parent->code) {}
 
        object *resolve_forwarding(object *untagged)
        {
@@ -39,8 +41,10 @@ template<typename TargetGeneration, typename Policy> struct data_workhorse {
                return newpointer;
        }
 
-       object *operator()(object *obj)
+       object *fixup_data(object *obj)
        {
+               parent->check_data_pointer(obj);
+
                if(!policy.should_copy_p(obj))
                {
                        policy.visited_object(obj);
@@ -59,17 +63,18 @@ template<typename TargetGeneration, typename Policy> struct data_workhorse {
                        return forwarding;
                }
        }
-};
 
-template<typename TargetGeneration, typename Policy>
-inline static slot_visitor<data_workhorse<TargetGeneration,Policy> > make_data_visitor(
-       factor_vm *parent,
-       TargetGeneration *target,
-       Policy policy)
-{
-       return slot_visitor<data_workhorse<TargetGeneration,Policy> >(parent,
-               data_workhorse<TargetGeneration,Policy>(parent,target,policy));
-}
+       code_block *fixup_code(code_block *compiled)
+       {
+               if(!code->marked_p(compiled))
+               {
+                       code->set_marked_p(compiled);
+                       parent->mark_stack.push_back((cell)compiled + 1);
+               }
+
+               return compiled;
+       }
+};
 
 struct dummy_unmarker {
        void operator()(card *ptr) {}
@@ -92,7 +97,8 @@ struct collector {
        data_heap *data;
        code_heap *code;
        TargetGeneration *target;
-       slot_visitor<data_workhorse<TargetGeneration,Policy> > data_visitor;
+       gc_workhorse<TargetGeneration,Policy> workhorse;
+       slot_visitor<gc_workhorse<TargetGeneration,Policy> > data_visitor;
        cell cards_scanned;
        cell decks_scanned;
        cell code_blocks_scanned;
@@ -102,7 +108,8 @@ struct collector {
                data(parent_->data),
                code(parent_->code),
                target(target_),
-               data_visitor(make_data_visitor(parent_,target_,policy_)),
+               workhorse(parent,target,policy_),
+               data_visitor(parent,workhorse),
                cards_scanned(0),
                decks_scanned(0),
                code_blocks_scanned(0) {}
index 5e52c70b0c852cd1385b9865e7e2d2d99da02873..9d26062a5c498895b9b7ec2f527f26be4118284b 100644 (file)
 
 namespace factor {
 
-template<typename Block> struct forwarder {
-       mark_bits<Block> *forwarding_map;
+struct compaction_fixup {
+       mark_bits<object> *data_forwarding_map;
+       mark_bits<code_block> *code_forwarding_map;
+       const object **data_finger;
+       const code_block **code_finger;
 
-       explicit forwarder(mark_bits<Block> *forwarding_map_) :
-               forwarding_map(forwarding_map_) {}
+       explicit compaction_fixup(
+               mark_bits<object> *data_forwarding_map_,
+               mark_bits<code_block> *code_forwarding_map_,
+               const object **data_finger_,
+               const code_block **code_finger_) :
+               data_forwarding_map(data_forwarding_map_),
+               code_forwarding_map(code_forwarding_map_),
+               data_finger(data_finger_),
+               code_finger(code_finger_) {}
 
-       Block *operator()(Block *block)
+       object *fixup_data(object *obj)
        {
-               return forwarding_map->forward_block(block);
+               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)
+       code_block *fixup_code(code_block *compiled)
        {
-               /* It's already been moved up; dereference through forwarding
-               map to get the size */
-               layout = (tuple_layout *)forwarding_map->forward_block(layout_obj);
+               return code_forwarding_map->forward_block(compiled);
        }
-       else
+
+       object *translate_data(const object *obj)
        {
-               /* It hasn't been moved up yet; dereference directly */
-               layout = (tuple_layout *)layout_obj;
+               if(obj < *data_finger)
+                       return fixup_data((object *)obj);
+               else
+                       return (object *)obj;
        }
 
-       return tuple_size(layout);
-}
-
-struct compaction_sizer {
-       mark_bits<object> *forwarding_map;
+       code_block *translate_code(const code_block *compiled)
+       {
+               if(compiled < *code_finger)
+                       return fixup_code((code_block *)compiled);
+               else
+                       return (code_block *)compiled;
+       }
 
-       explicit compaction_sizer(mark_bits<object> *forwarding_map_) :
-               forwarding_map(forwarding_map_) {}
+       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 operator()(object *obj)
+       cell size(code_block *compiled)
        {
-               if(!forwarding_map->marked_p(obj))
-                       return forwarding_map->unmarked_block_size(obj);
-               else if(obj->type() == TUPLE_TYPE)
-                       return align(tuple_size_with_forwarding(forwarding_map,obj),data_alignment);
+               if(code_forwarding_map->marked_p(compiled))
+                       return compiled->size(*this);
                else
-                       return obj->size();
+                       return code_forwarding_map->unmarked_block_size(compiled);
        }
 };
 
 struct object_compaction_updater {
        factor_vm *parent;
-       mark_bits<code_block> *code_forwarding_map;
-       mark_bits<object> *data_forwarding_map;
+       compaction_fixup fixup;
        object_start_map *starts;
 
-       explicit object_compaction_updater(factor_vm *parent_,
-               mark_bits<object> *data_forwarding_map_,
-               mark_bits<code_block> *code_forwarding_map_) :
+       explicit object_compaction_updater(factor_vm *parent_, compaction_fixup fixup_) :
                parent(parent_),
-               code_forwarding_map(code_forwarding_map_),
-               data_forwarding_map(data_forwarding_map_),
+               fixup(fixup_),
                starts(&parent->data->tenured->starts) {}
 
        void operator()(object *old_address, object *new_address, cell size)
        {
-               cell payload_start;
-               if(old_address->type() == TUPLE_TYPE)
-                       payload_start = tuple_size_with_forwarding(data_forwarding_map,old_address);
-               else
-                       payload_start = old_address->binary_payload_start();
-
-               memmove(new_address,old_address,size);
+               slot_visitor<compaction_fixup> slot_forwarder(parent,fixup);
+               slot_forwarder.visit_slots(new_address);
 
-               slot_visitor<forwarder<object> > slot_forwarder(parent,forwarder<object>(data_forwarding_map));
-               slot_forwarder.visit_slots(new_address,payload_start);
-
-               code_block_visitor<forwarder<code_block> > code_forwarder(parent,forwarder<code_block>(code_forwarding_map));
+               code_block_visitor<compaction_fixup> code_forwarder(parent,fixup);
                code_forwarder.visit_object_code_block(new_address);
 
                starts->record_object_start_offset(new_address);
        }
 };
 
-template<typename SlotForwarder>
+template<typename Fixup>
 struct code_block_compaction_relocation_visitor {
        factor_vm *parent;
        code_block *old_address;
-       slot_visitor<SlotForwarder> slot_forwarder;
-       code_block_visitor<forwarder<code_block> > code_forwarder;
+       Fixup fixup;
 
        explicit code_block_compaction_relocation_visitor(factor_vm *parent_,
                code_block *old_address_,
-               slot_visitor<SlotForwarder> slot_forwarder_,
-               code_block_visitor<forwarder<code_block> > code_forwarder_) :
+               Fixup fixup_) :
                parent(parent_),
                old_address(old_address_),
-               slot_forwarder(slot_forwarder_),
-               code_forwarder(code_forwarder_) {}
+               fixup(fixup_) {}
 
        void operator()(instruction_operand op)
        {
@@ -109,16 +103,25 @@ struct code_block_compaction_relocation_visitor {
                switch(op.rel_type())
                {
                case RT_LITERAL:
-                       op.store_value(slot_forwarder.visit_pointer(op.load_value(old_offset)));
-                       break;
+                       {
+                               cell value = op.load_value(old_offset);
+                               if(immediate_p(value))
+                                       op.store_value(value);
+                               else
+                                       op.store_value(RETAG(fixup.fixup_data(untag<object>(value)),TAG(value)));
+                               break;
+                       }
                case RT_ENTRY_POINT:
                case RT_ENTRY_POINT_PIC:
                case RT_ENTRY_POINT_PIC_TAIL:
-                       op.store_code_block(code_forwarder.visit_code_block(op.load_code_block(old_offset)));
-                       break;
                case RT_HERE:
-                       op.store_value(op.load_value(old_offset) - (cell)old_address + (cell)op.parent_code_block());
-                       break;
+                       {
+                               cell value = op.load_value(old_offset);
+                               cell offset = TAG(value);
+                               code_block *compiled = (code_block *)UNTAG(value);
+                               op.store_value((cell)fixup.fixup_code(compiled) + offset);
+                               break;
+                       }
                case RT_THIS:
                case RT_CARDS_OFFSET:
                case RT_DECKS_OFFSET:
@@ -131,26 +134,27 @@ struct code_block_compaction_relocation_visitor {
        }
 };
 
-template<typename SlotForwarder>
+template<typename Fixup>
 struct code_block_compaction_updater {
        factor_vm *parent;
-       slot_visitor<SlotForwarder> slot_forwarder;
-       code_block_visitor<forwarder<code_block> > code_forwarder;
+       Fixup fixup;
+       slot_visitor<Fixup> data_forwarder;
+       code_block_visitor<Fixup> code_forwarder;
 
        explicit code_block_compaction_updater(factor_vm *parent_,
-               slot_visitor<SlotForwarder> slot_forwarder_,
-               code_block_visitor<forwarder<code_block> > code_forwarder_) :
+               Fixup fixup_,
+               slot_visitor<Fixup> data_forwarder_,
+               code_block_visitor<Fixup> code_forwarder_) :
                parent(parent_),
-               slot_forwarder(slot_forwarder_),
+               fixup(fixup_),
+               data_forwarder(data_forwarder_),
                code_forwarder(code_forwarder_) {}
 
        void operator()(code_block *old_address, code_block *new_address, cell size)
        {
-               memmove(new_address,old_address,size);
+               data_forwarder.visit_code_block_objects(new_address);
 
-               slot_forwarder.visit_code_block_objects(new_address);
-
-               code_block_compaction_relocation_visitor<SlotForwarder> visitor(parent,old_address,slot_forwarder,code_forwarder);
+               code_block_compaction_relocation_visitor<Fixup> visitor(parent,old_address,fixup);
                new_address->each_instruction_operand(visitor);
        }
 };
@@ -196,8 +200,12 @@ void factor_vm::collect_compact_impl(bool trace_contexts_p)
        data_forwarding_map->compute_forwarding();
        code_forwarding_map->compute_forwarding();
 
-       slot_visitor<forwarder<object> > slot_forwarder(this,forwarder<object>(data_forwarding_map));
-       code_block_visitor<forwarder<code_block> > code_forwarder(this,forwarder<code_block>(code_forwarding_map));
+       const object *data_finger = tenured->first_block();
+       const code_block *code_finger = code->allocator->first_block();
+
+       compaction_fixup fixup(data_forwarding_map,code_forwarding_map,&data_finger,&code_finger);
+       slot_visitor<compaction_fixup> data_forwarder(this,fixup);
+       code_block_visitor<compaction_fixup> code_forwarder(this,fixup);
 
        code_forwarder.visit_uninitialized_code_blocks();
 
@@ -206,20 +214,18 @@ void factor_vm::collect_compact_impl(bool trace_contexts_p)
 
        /* Slide everything in tenured space up, and update data and code heap
        pointers inside objects. */
-       object_compaction_updater object_updater(this,data_forwarding_map,code_forwarding_map);
-       compaction_sizer object_sizer(data_forwarding_map);
-       tenured->compact(object_updater,object_sizer);
+       object_compaction_updater object_updater(this,fixup);
+       tenured->compact(object_updater,fixup,&data_finger);
 
        /* Slide everything in the code heap up, and update data and code heap
        pointers inside code blocks. */
-       code_block_compaction_updater<forwarder<object> > code_block_updater(this,slot_forwarder,code_forwarder);
-       standard_sizer<code_block> code_block_sizer;
-       code->allocator->compact(code_block_updater,code_block_sizer);
+       code_block_compaction_updater<compaction_fixup> code_block_updater(this,fixup,data_forwarder,code_forwarder);
+       code->allocator->compact(code_block_updater,fixup,&code_finger);
 
-       slot_forwarder.visit_roots();
+       data_forwarder.visit_roots();
        if(trace_contexts_p)
        {
-               slot_forwarder.visit_contexts();
+               data_forwarder.visit_contexts();
                code_forwarder.visit_context_code_blocks();
        }
 
@@ -229,10 +235,56 @@ void factor_vm::collect_compact_impl(bool trace_contexts_p)
        current_gc->event->ended_compaction();
 }
 
+struct code_compaction_fixup {
+       mark_bits<code_block> *code_forwarding_map;
+       const code_block **code_finger;
+
+       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<forwarder<code_block> > code_forwarder;
+       code_block_visitor<code_compaction_fixup> code_forwarder;
 
-       explicit object_grow_heap_updater(code_block_visitor<forwarder<code_block> > code_forwarder_) :
+       explicit object_grow_heap_updater(code_block_visitor<code_compaction_fixup> code_forwarder_) :
                code_forwarder(code_forwarder_) {}
 
        void operator()(object *obj)
@@ -241,10 +293,6 @@ struct object_grow_heap_updater {
        }
 };
 
-struct dummy_slot_forwarder {
-       object *operator()(object *obj) { return obj; }
-};
-
 /* Compact just the code heap, after growing the data heap */
 void factor_vm::collect_compact_code_impl(bool trace_contexts_p)
 {
@@ -252,8 +300,11 @@ void factor_vm::collect_compact_code_impl(bool trace_contexts_p)
        mark_bits<code_block> *code_forwarding_map = &code->allocator->state;
        code_forwarding_map->compute_forwarding();
 
-       slot_visitor<dummy_slot_forwarder> slot_forwarder(this,dummy_slot_forwarder());
-       code_block_visitor<forwarder<code_block> > code_forwarder(this,forwarder<code_block>(code_forwarding_map));
+       const code_block *code_finger = code->allocator->first_block();
+
+       code_compaction_fixup fixup(code_forwarding_map,&code_finger);
+       slot_visitor<code_compaction_fixup> data_forwarder(this,fixup);
+       code_block_visitor<code_compaction_fixup> code_forwarder(this,fixup);
 
        code_forwarder.visit_uninitialized_code_blocks();
 
@@ -261,14 +312,13 @@ void factor_vm::collect_compact_code_impl(bool trace_contexts_p)
                code_forwarder.visit_context_code_blocks();
 
        /* Update code heap references in data heap */
-       object_grow_heap_updater updater(code_forwarder);
-       each_object(updater);
+       object_grow_heap_updater object_updater(code_forwarder);
+       each_object(object_updater);
 
        /* Slide everything in the code heap up, and update code heap
        pointers inside code blocks. */
-       code_block_compaction_updater<dummy_slot_forwarder> code_block_updater(this,slot_forwarder,code_forwarder);
-       standard_sizer<code_block> code_block_sizer;
-       code->allocator->compact(code_block_updater,code_block_sizer);
+       code_block_compaction_updater<code_compaction_fixup> code_block_updater(this,fixup,data_forwarder,code_forwarder);
+       code->allocator->compact(code_block_updater,fixup,&code_finger);
 
        update_code_roots_for_compaction();
        callbacks->update();
index 25fe0e5280cc43a82617111119e981303ec6424b..8ec3363662652c3c194d4d3b9f4be7668f97d6e8 100644 (file)
@@ -55,6 +55,41 @@ void context::fix_stacks()
                reset_retainstack();
 }
 
+void context::scrub_stacks(gc_info *info, cell index)
+{
+       u8 *bitmap = info->gc_info_bitmap();
+
+       {
+               cell base = info->scrub_d_base(index);
+
+               for(cell loc = 0; loc < info->scrub_d_count; loc++)
+               {
+                       if(bitmap_p(bitmap,base + loc))
+                       {
+#ifdef DEBUG_GC_MAPS
+                               std::cout << "scrubbing datastack location " << loc << std::endl;
+#endif
+                               ((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))
+                       {
+#ifdef DEBUG_GC_MAPS
+                               std::cout << "scrubbing retainstack location " << loc << std::endl;
+#endif
+                               ((cell *)retainstack)[-loc] = 0;
+                       }
+               }
+       }
+}
+
 context::~context()
 {
        delete datastack_seg;
index 582fab173f9bc7a0c7b3c89c161d50ba5b10fca0..4aa7d7c221b215af99c37155db37cf355569bb32 100644 (file)
@@ -45,6 +45,7 @@ struct context {
        void reset_context_objects();
        void reset();
        void fix_stacks();
+       void scrub_stacks(gc_info *info, cell index);
 
        cell peek()
        {
index 9b28215bb835d7a236b2a7837a6796b3ebb1dd97..3648ba7f4827c7acf00a75694048beab30384c66 100755 (executable)
@@ -126,85 +126,6 @@ void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_si
        set_data_heap(new data_heap(young_size,aging_size,tenured_size));
 }
 
-/* Size of the object pointed to by an untagged pointer */
-cell object::size() const
-{
-       if(free_p()) return ((free_heap_block *)this)->size();
-
-       switch(type())
-       {
-       case ARRAY_TYPE:
-               return align(array_size((array*)this),data_alignment);
-       case BIGNUM_TYPE:
-               return align(array_size((bignum*)this),data_alignment);
-       case BYTE_ARRAY_TYPE:
-               return align(array_size((byte_array*)this),data_alignment);
-       case STRING_TYPE:
-               return align(string_size(string_capacity((string*)this)),data_alignment);
-       case TUPLE_TYPE:
-               {
-                       tuple_layout *layout = (tuple_layout *)UNTAG(((tuple *)this)->layout);
-                       return align(tuple_size(layout),data_alignment);
-               }
-       case QUOTATION_TYPE:
-               return align(sizeof(quotation),data_alignment);
-       case WORD_TYPE:
-               return align(sizeof(word),data_alignment);
-       case FLOAT_TYPE:
-               return align(sizeof(boxed_float),data_alignment);
-       case DLL_TYPE:
-               return align(sizeof(dll),data_alignment);
-       case ALIEN_TYPE:
-               return align(sizeof(alien),data_alignment);
-       case WRAPPER_TYPE:
-               return align(sizeof(wrapper),data_alignment);
-       case CALLSTACK_TYPE:
-               return align(callstack_object_size(untag_fixnum(((callstack *)this)->length)),data_alignment);
-       default:
-               critical_error("Invalid header",(cell)this);
-               return 0; /* can't happen */
-       }
-}
-
-/* The number of cells from the start of the object which should be scanned by
-the GC. Some types have a binary payload at the end (string, word, DLL) which
-we ignore. */
-cell object::binary_payload_start() const
-{
-       if(free_p()) return 0;
-
-       switch(type())
-       {
-       /* these objects do not refer to other objects at all */
-       case FLOAT_TYPE:
-       case BYTE_ARRAY_TYPE:
-       case BIGNUM_TYPE:
-       case CALLSTACK_TYPE:
-               return 0;
-       /* these objects have some binary data at the end */
-       case WORD_TYPE:
-               return sizeof(word) - sizeof(cell) * 3;
-       case ALIEN_TYPE:
-               return sizeof(cell) * 3;
-       case DLL_TYPE:
-               return sizeof(cell) * 2;
-       case QUOTATION_TYPE:
-               return sizeof(quotation) - sizeof(cell) * 2;
-       case STRING_TYPE:
-               return sizeof(string);
-       /* everything else consists entirely of pointers */
-       case ARRAY_TYPE:
-               return array_size<array>(array_capacity((array*)this));
-       case TUPLE_TYPE:
-               return tuple_size(untag<tuple_layout>(((tuple *)this)->layout));
-       case WRAPPER_TYPE:
-               return sizeof(wrapper);
-       default:
-               critical_error("Invalid header",(cell)this);
-               return 0; /* can't happen */
-       }
-}
-
 data_heap_room factor_vm::data_room()
 {
        data_heap_room room;
diff --git a/vm/fixup.hpp b/vm/fixup.hpp
new file mode 100644 (file)
index 0000000..c92661a
--- /dev/null
@@ -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();
+       }
+};
+
+}
index 4c725bcf4f401961ff7b4e5605dbd1d0eedcc73f..7d7807ef9ab71dcb5d4df8e0132c7d775f2c5033 100644 (file)
@@ -23,8 +23,8 @@ template<typename Block> struct free_list_allocator {
        cell largest_free_block();
        cell free_block_count();
        void sweep();
-       template<typename Iterator, typename Sizer> void compact(Iterator &iter, Sizer &sizer);
-       template<typename Iterator, typename Sizer> void iterate(Iterator &iter, Sizer &sizer);
+       template<typename Iterator, typename Fixup> void compact(Iterator &iter, Fixup fixup, const Block **finger);
+       template<typename Iterator, typename Fixup> void iterate(Iterator &iter, Fixup fixup);
        template<typename Iterator> void iterate(Iterator &iter);
 };
 
@@ -155,14 +155,17 @@ template<typename Block, typename Iterator> struct heap_compactor {
        mark_bits<Block> *state;
        char *address;
        Iterator &iter;
+       const Block **finger;
 
-       explicit heap_compactor(mark_bits<Block> *state_, Block *address_, Iterator &iter_) :
-               state(state_), address((char *)address_), iter(iter_) {}
+       explicit heap_compactor(mark_bits<Block> *state_, Block *address_, Iterator &iter_, const Block **finger_) :
+               state(state_), address((char *)address_), iter(iter_), finger(finger_) {}
 
        void operator()(Block *block, cell size)
        {
                if(this->state->marked_p(block))
                {
+                       *finger = block;
+                       memmove((Block *)address,block,size);
                        iter(block,(Block *)address,size);
                        address += size;
                }
@@ -172,11 +175,11 @@ template<typename Block, typename Iterator> struct heap_compactor {
 /* The forwarding map must be computed first by calling
 state.compute_forwarding(). */
 template<typename Block>
-template<typename Iterator, typename Sizer>
-void free_list_allocator<Block>::compact(Iterator &iter, Sizer &sizer)
+template<typename Iterator, typename Fixup>
+void free_list_allocator<Block>::compact(Iterator &iter, Fixup fixup, const Block **finger)
 {
-       heap_compactor<Block,Iterator> compactor(&state,first_block(),iter);
-       iterate(compactor,sizer);
+       heap_compactor<Block,Iterator> compactor(&state,first_block(),iter,finger);
+       iterate(compactor,fixup);
 
        /* Now update the free list; there will be a single free block at
        the end */
@@ -185,34 +188,26 @@ void free_list_allocator<Block>::compact(Iterator &iter, Sizer &sizer)
 
 /* During compaction we have to be careful and measure object sizes differently */
 template<typename Block>
-template<typename Iterator, typename Sizer>
-void free_list_allocator<Block>::iterate(Iterator &iter, Sizer &sizer)
+template<typename Iterator, typename Fixup>
+void free_list_allocator<Block>::iterate(Iterator &iter, Fixup fixup)
 {
        Block *scan = first_block();
        Block *end = last_block();
 
        while(scan != end)
        {
-               cell size = sizer(scan);
+               cell size = fixup.size(scan);
                Block *next = (Block *)((cell)scan + size);
                if(!scan->free_p()) iter(scan,size);
                scan = next;
        }
 }
 
-template<typename Block> struct standard_sizer {
-       cell operator()(Block *block)
-       {
-               return block->size();
-       }
-};
-
 template<typename Block>
 template<typename Iterator>
 void free_list_allocator<Block>::iterate(Iterator &iter)
 {
-       standard_sizer<Block> sizer;
-       iterate(iter,sizer);
+       iterate(iter,no_fixup());
 }
 
 }
index 849ef07084493e7d31a81437e77c4c3106e9ebbc..19d8b576a5bcbf7b77cb7ca8ec50814276ae1628 100644 (file)
@@ -3,17 +3,9 @@
 namespace factor
 {
 
-inline static code_block_visitor<code_workhorse> make_code_visitor(factor_vm *parent)
-{
-       return code_block_visitor<code_workhorse>(parent,code_workhorse(parent));
-}
-
 full_collector::full_collector(factor_vm *parent_) :
-       collector<tenured_space,full_policy>(
-               parent_,
-               parent_->data->tenured,
-               full_policy(parent_)),
-       code_visitor(make_code_visitor(parent_)) {}
+       collector<tenured_space,full_policy>(parent_,parent_->data->tenured,full_policy(parent_)),
+       code_visitor(parent,workhorse) {}
 
 void full_collector::trace_code_block(code_block *compiled)
 {
index ba859e28c93c63a6cd63d9b379b4800ee52a30ce..82a057ddbfb726a5077d5971c20b60b601627b90 100644 (file)
@@ -25,26 +25,8 @@ struct full_policy {
        }
 };
 
-struct code_workhorse {
-       factor_vm *parent;
-       code_heap *code;
-
-       explicit code_workhorse(factor_vm *parent_) : parent(parent_), code(parent->code) {}
-
-       code_block *operator()(code_block *compiled)
-       {
-               if(!code->marked_p(compiled))
-               {
-                       code->set_marked_p(compiled);
-                       parent->mark_stack.push_back((cell)compiled + 1);
-               }
-
-               return compiled;
-       }
-};
-
 struct full_collector : collector<tenured_space,full_policy> {
-       code_block_visitor<code_workhorse> code_visitor;
+       code_block_visitor<gc_workhorse<tenured_space,full_policy> > code_visitor;
 
        explicit full_collector(factor_vm *parent_);
        void trace_code_block(code_block *compiled);
index 599ed3cd31ef7bbedd2369930ce3927218793d51..766940a2d7160ab1152446c3b95a5b4f9ea3c72d 100755 (executable)
--- a/vm/gc.cpp
+++ b/vm/gc.cpp
@@ -194,8 +194,54 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
        current_gc = NULL;
 }
 
+/* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
+uninitialized stack locations before actually calling the GC. See the comment
+in compiler.cfg.stacks.uninitialized for details. */
+
+struct call_frame_scrubber {
+       factor_vm *parent;
+       context *ctx;
+
+       explicit call_frame_scrubber(factor_vm *parent_, context *ctx_) :
+               parent(parent_), ctx(ctx_) {}
+
+       void operator()(stack_frame *frame)
+       {
+               cell return_address = parent->frame_offset(frame);
+               if(return_address == (cell)-1)
+                       return;
+
+               code_block *compiled = parent->frame_code(frame);
+               gc_info *info = compiled->block_gc_info();
+
+               assert(return_address < compiled->size());
+               int index = info->return_address_index(return_address);
+               if(index != -1)
+                       ctx->scrub_stacks(info,index);
+       }
+};
+
+void factor_vm::scrub_context(context *ctx)
+{
+       call_frame_scrubber scrubber(this,ctx);
+       iterate_callstack(ctx,scrubber);
+}
+
+void factor_vm::scrub_contexts()
+{
+       std::set<context *>::const_iterator begin = active_contexts.begin();
+       std::set<context *>::const_iterator end = active_contexts.end();
+       while(begin != end)
+       {
+               scrub_context(*begin);
+               begin++;
+       }
+}
+
 void factor_vm::primitive_minor_gc()
 {
+       scrub_contexts();
+
        gc(collect_nursery_op,
                0, /* requested size */
                true /* trace contexts? */);
@@ -215,36 +261,6 @@ void factor_vm::primitive_compact_gc()
                true /* trace contexts? */);
 }
 
-void factor_vm::inline_gc(cell gc_roots_)
-{
-       cell stack_pointer = (cell)ctx->callstack_top;
-
-       if(to_boolean(gc_roots_))
-       {
-               tagged<array> gc_roots(gc_roots_);
-
-               cell capacity = array_capacity(gc_roots.untagged());
-               for(cell i = 0; i < capacity; i++)
-               {
-                       cell spill_slot = untag_fixnum(array_nth(gc_roots.untagged(),i));
-                       cell *address = (cell *)(spill_slot + stack_pointer);
-                       data_roots.push_back(data_root_range(address,1));
-               }
-
-               primitive_minor_gc();
-
-               for(cell i = 0; i < capacity; i++)
-                       data_roots.pop_back();
-       }
-       else
-               primitive_minor_gc();
-}
-
-VM_C_API void inline_gc(cell gc_roots, factor_vm *parent)
-{
-       parent->inline_gc(gc_roots);
-}
-
 /*
  * It is up to the caller to fill in the object's fields in a meaningful
  * fashion!
index 39a69e34f4c0678ee93ffd964fcc74a5754df26a..f6e9a875a63c04bbf165b155f9421885af6f89a0 100755 (executable)
--- a/vm/gc.hpp
+++ b/vm/gc.hpp
@@ -52,6 +52,4 @@ struct gc_state {
        void start_again(gc_op op_, factor_vm *parent);
 };
 
-VM_C_API void inline_gc(cell gc_roots, factor_vm *parent);
-
 }
diff --git a/vm/gc_info.cpp b/vm/gc_info.cpp
new file mode 100644 (file)
index 0000000..b937d0a
--- /dev/null
@@ -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;
+}
+
+}
diff --git a/vm/gc_info.hpp b/vm/gc_info.hpp
new file mode 100644 (file)
index 0000000..d5229a1
--- /dev/null
@@ -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);
+};
+
+}
index ccce96a952c56970c8b728293989347173338bc6..4643d897797bee7e66325dc7683b7f6ab304284d 100755 (executable)
@@ -55,70 +55,66 @@ void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p)
        code->allocator->initial_free_list(h->code_size);
 }
 
-struct data_fixupper {
-       cell offset;
+struct startup_fixup {
+       cell data_offset;
+       cell code_offset;
 
-       explicit data_fixupper(cell offset_) : offset(offset_) {}
+       explicit startup_fixup(cell data_offset_, cell code_offset_) :
+               data_offset(data_offset_), code_offset(code_offset_) {}
 
-       object *operator()(object *obj)
+       object *fixup_data(object *obj)
        {
-               return (object *)((char *)obj + offset);
+               return (object *)((cell)obj + data_offset);
        }
-};
-
-struct code_fixupper {
-       cell offset;
-
-       explicit code_fixupper(cell offset_) : offset(offset_) {}
 
-       code_block *operator()(code_block *compiled)
+       code_block *fixup_code(code_block *obj)
        {
-               return (code_block *)((char *)compiled + offset);
+               return (code_block *)((cell)obj + code_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);
-}
+       object *translate_data(const object *obj)
+       {
+               return fixup_data((object *)obj);
+       }
 
-struct fixup_sizer {
-       cell offset;
+       code_block *translate_code(const code_block *compiled)
+       {
+               return fixup_code((code_block *)compiled);
+       }
 
-       explicit fixup_sizer(cell offset_) : offset(offset_) {}
+       cell size(const object *obj)
+       {
+               return obj->size(*this);
+       }
 
-       cell operator()(object *obj)
+       cell size(code_block *compiled)
        {
-               if(obj->type() == TUPLE_TYPE)
-                       return align(tuple_size_with_fixup(offset,obj),data_alignment);
-               else
-                       return obj->size();
+               return compiled->size(*this);
        }
 };
 
-struct object_fixupper {
+struct start_object_updater {
        factor_vm *parent;
-       cell data_offset;
-       slot_visitor<data_fixupper> data_visitor;
-       code_block_visitor<code_fixupper> code_visitor;
+       startup_fixup fixup;
+       slot_visitor<startup_fixup> data_visitor;
+       code_block_visitor<startup_fixup> code_visitor;
 
-       object_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) :
+       start_object_updater(factor_vm *parent_, startup_fixup fixup_) :
                parent(parent_),
-               data_offset(data_offset_),
-               data_visitor(slot_visitor<data_fixupper>(parent_,data_fixupper(data_offset_))),
-               code_visitor(code_block_visitor<code_fixupper>(parent_,code_fixupper(code_offset_))) {}
+               fixup(fixup_),
+               data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)),
+               code_visitor(code_block_visitor<startup_fixup>(parent_,fixup_)) {}
 
        void operator()(object *obj, cell size)
        {
                parent->data->tenured->starts.record_object_start_offset(obj);
 
+               data_visitor.visit_slots(obj);
+
                switch(obj->type())
                {
                case ALIEN_TYPE:
                        {
-                               cell payload_start = obj->binary_payload_start();
-                               data_visitor.visit_slots(obj,payload_start);
 
                                alien *ptr = (alien *)obj;
 
@@ -130,22 +126,11 @@ struct object_fixupper {
                        }
                case DLL_TYPE:
                        {
-                               cell payload_start = obj->binary_payload_start();
-                               data_visitor.visit_slots(obj,payload_start);
-
                                parent->ffi_dlopen((dll *)obj);
                                break;
                        }
-               case TUPLE_TYPE:
-                       {
-                               cell payload_start = tuple_size_with_fixup(data_offset,obj);
-                               data_visitor.visit_slots(obj,payload_start);
-                               break;
-                       }
                default:
                        {
-                               cell payload_start = obj->binary_payload_start();
-                               data_visitor.visit_slots(obj,payload_start);
                                code_visitor.visit_object_code_block(obj);
                                break;
                        }
@@ -155,44 +140,51 @@ struct object_fixupper {
 
 void factor_vm::fixup_data(cell data_offset, cell code_offset)
 {
-       slot_visitor<data_fixupper> data_workhorse(this,data_fixupper(data_offset));
+       startup_fixup fixup(data_offset,code_offset);
+       slot_visitor<startup_fixup> data_workhorse(this,fixup);
        data_workhorse.visit_roots();
 
-       object_fixupper fixupper(this,data_offset,code_offset);
-       fixup_sizer sizer(data_offset);
-       data->tenured->iterate(fixupper,sizer);
+       start_object_updater updater(this,fixup);
+       data->tenured->iterate(updater,fixup);
 }
 
-struct code_block_fixup_relocation_visitor {
+struct startup_code_block_relocation_visitor {
        factor_vm *parent;
-       cell code_offset;
-       slot_visitor<data_fixupper> data_visitor;
-       code_fixupper code_visitor;
+       startup_fixup fixup;
+       slot_visitor<startup_fixup> data_visitor;
 
-       code_block_fixup_relocation_visitor(factor_vm *parent_, cell data_offset_, cell code_offset_) :
+       startup_code_block_relocation_visitor(factor_vm *parent_, startup_fixup fixup_) :
                parent(parent_),
-               code_offset(code_offset_),
-               data_visitor(slot_visitor<data_fixupper>(parent_,data_fixupper(data_offset_))),
-               code_visitor(code_fixupper(code_offset_)) {}
+               fixup(fixup_),
+               data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)) {}
 
        void operator()(instruction_operand op)
        {
                code_block *compiled = op.parent_code_block();
-               cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - code_offset;
+               cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - fixup.code_offset;
 
                switch(op.rel_type())
                {
                case RT_LITERAL:
-                       op.store_value(data_visitor.visit_pointer(op.load_value(old_offset)));
-                       break;
+                       {
+                               cell value = op.load_value(old_offset);
+                               if(immediate_p(value))
+                                       op.store_value(value);
+                               else
+                                       op.store_value(RETAG(fixup.fixup_data(untag<object>(value)),TAG(value)));
+                               break;
+                       }
                case RT_ENTRY_POINT:
                case RT_ENTRY_POINT_PIC:
                case RT_ENTRY_POINT_PIC_TAIL:
-                       op.store_code_block(code_visitor(op.load_code_block(old_offset)));
-                       break;
                case RT_HERE:
-                       op.store_value(op.load_value(old_offset) + code_offset);
-                       break;
+                       {
+                               cell value = op.load_value(old_offset);
+                               cell offset = TAG(value);
+                               code_block *compiled = (code_block *)UNTAG(value);
+                               op.store_value((cell)fixup.fixup_code(compiled) + offset);
+                               break;
+                       }
                case RT_UNTAGGED:
                        break;
                default:
@@ -202,30 +194,28 @@ struct code_block_fixup_relocation_visitor {
        }
 };
 
-struct code_block_fixupper {
+struct startup_code_block_updater {
        factor_vm *parent;
-       cell data_offset;
-       cell code_offset;
+       startup_fixup fixup;
 
-       code_block_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) :
-               parent(parent_),
-               data_offset(data_offset_),
-               code_offset(code_offset_) {}
+       startup_code_block_updater(factor_vm *parent_, startup_fixup fixup_) :
+               parent(parent_), fixup(fixup_) {}
 
        void operator()(code_block *compiled, cell size)
        {
-               slot_visitor<data_fixupper> data_visitor(parent,data_fixupper(data_offset));
+               slot_visitor<startup_fixup> data_visitor(parent,fixup);
                data_visitor.visit_code_block_objects(compiled);
 
-               code_block_fixup_relocation_visitor code_visitor(parent,data_offset,code_offset);
+               startup_code_block_relocation_visitor code_visitor(parent,fixup);
                compiled->each_instruction_operand(code_visitor);
        }
 };
 
 void factor_vm::fixup_code(cell data_offset, cell code_offset)
 {
-       code_block_fixupper fixupper(this,data_offset,code_offset);
-       code->allocator->iterate(fixupper);
+       startup_fixup fixup(data_offset,code_offset);
+       startup_code_block_updater updater(this,fixup);
+       code->allocator->iterate(updater,fixup);
 }
 
 /* Read an image file from disk, only done once during startup */
index 3324cfb366179a28926b8d7c0e405ea910827976..b98c6f54ff8d0fda2c67225ef95df1c6142e7ad2 100644 (file)
@@ -116,6 +116,11 @@ void jit::compute_position(cell offset_)
 /* Allocates memory */
 code_block *jit::to_code_block()
 {
+       /* Emit dummy GC info */
+       code.grow_bytes(alignment_for(code.count + 4,data_alignment));
+       u32 dummy_gc_info = 0;
+       code.append_bytes(&dummy_gc_info,sizeof(u32));
+
        code.trim();
        relocation.trim();
        parameters.trim();
index 5e7ca0279f73582e1476c895ff4e8dc4939169c7..b0edb4be164d7691e6446cf80334859af555fcfc 100644 (file)
@@ -23,6 +23,11 @@ inline static cell align(cell a, cell b)
        return (a + (b-1)) & ~(b-1);
 }
 
+inline static cell alignment_for(cell a, cell b)
+{
+       return align(a,b) - a;
+}
+
 static const cell data_alignment = 16;
 
 #define WORD_SIZE (signed)(sizeof(cell)*8)
@@ -98,7 +103,10 @@ struct object {
        cell header;
 
        cell size() const;
+       template<typename Fixup> cell size(Fixup fixup) const;
+
        cell binary_payload_start() const;
+       template<typename Fixup> cell binary_payload_start(Fixup fixup) const;
 
        cell *slots() const { return (cell *)this; }
 
index 5115f9a8214489045451d054ac8ec724c6bfea77..b3b73ba1ea86aba00d6123d8ea77e44f0a264e1a 100644 (file)
@@ -40,7 +40,7 @@ template<typename Block> struct mark_bits {
                forwarding = NULL;
        }
 
-       cell block_line(Block *address)
+       cell block_line(const Block *address)
        {
                return (((cell)address - start) / data_alignment);
        }
@@ -50,7 +50,7 @@ template<typename Block> struct mark_bits {
                return (Block *)(line * data_alignment + start);
        }
 
-       std::pair<cell,cell> bitmap_deref(Block *address)
+       std::pair<cell,cell> bitmap_deref(const Block *address)
        {
                cell line_number = block_line(address);
                cell word_index = (line_number / mark_bits_granularity);
@@ -58,18 +58,18 @@ template<typename Block> struct mark_bits {
                return std::make_pair(word_index,word_shift);
        }
 
-       bool bitmap_elt(cell *bits, Block *address)
+       bool bitmap_elt(cell *bits, const Block *address)
        {
                std::pair<cell,cell> position = bitmap_deref(address);
                return (bits[position.first] & ((cell)1 << position.second)) != 0;
        }
 
-       Block *next_block_after(Block *block)
+       Block *next_block_after(const Block *block)
        {
                return (Block *)((cell)block + block->size());
        }
 
-       void set_bitmap_range(cell *bits, Block *address)
+       void set_bitmap_range(cell *bits, const Block *address)
        {
                std::pair<cell,cell> start = bitmap_deref(address);
                std::pair<cell,cell> end = bitmap_deref(next_block_after(address));
@@ -99,12 +99,12 @@ template<typename Block> struct mark_bits {
                }
        }
 
-       bool marked_p(Block *address)
+       bool marked_p(const Block *address)
        {
                return bitmap_elt(marked,address);
        }
 
-       void set_marked_p(Block *address)
+       void set_marked_p(const Block *address)
        {
                set_bitmap_range(marked,address);
        }
@@ -123,7 +123,7 @@ template<typename Block> struct mark_bits {
 
        /* We have the popcount for every mark_bits_granularity entries; look
        up and compute the rest */
-       Block *forward_block(Block *original)
+       Block *forward_block(const Block *original)
        {
 #ifdef FACTOR_DEBUG
                assert(marked_p(original));
@@ -141,7 +141,7 @@ template<typename Block> struct mark_bits {
                return new_block;
        }
 
-       Block *next_unmarked_block_after(Block *original)
+       Block *next_unmarked_block_after(const Block *original)
        {
                std::pair<cell,cell> position = bitmap_deref(original);
                cell bit_index = position.second;
@@ -168,7 +168,7 @@ template<typename Block> struct mark_bits {
                return (Block *)(this->start + this->size);
        }
 
-       Block *next_marked_block_after(Block *original)
+       Block *next_marked_block_after(const Block *original)
        {
                std::pair<cell,cell> position = bitmap_deref(original);
                cell bit_index = position.second;
index a111a86b699be1d910347f1de2ef28f28adffa84..b8ababeb2da5ad7c499816fded34700ef2beea7e 100755 (executable)
@@ -75,6 +75,7 @@ namespace factor
 #include "platform.hpp"
 #include "primitives.hpp"
 #include "segments.hpp"
+#include "gc_info.hpp"
 #include "contexts.hpp"
 #include "run.hpp"
 #include "objects.hpp"
@@ -89,6 +90,8 @@ namespace factor
 #include "bitwise_hacks.hpp"
 #include "mark_bits.hpp"
 #include "free_list.hpp"
+#include "fixup.hpp"
+#include "tuples.hpp"
 #include "free_list_allocator.hpp"
 #include "write_barrier.hpp"
 #include "object_start_map.hpp"
@@ -100,7 +103,6 @@ namespace factor
 #include "gc.hpp"
 #include "debug.hpp"
 #include "strings.hpp"
-#include "tuples.hpp"
 #include "words.hpp"
 #include "float_bits.hpp"
 #include "io.hpp"
@@ -115,6 +117,7 @@ namespace factor
 #include "data_roots.hpp"
 #include "code_roots.hpp"
 #include "generic_arrays.hpp"
+#include "callstack.hpp"
 #include "slot_visitor.hpp"
 #include "collector.hpp"
 #include "copying_collector.hpp"
@@ -124,7 +127,6 @@ namespace factor
 #include "code_block_visitor.hpp"
 #include "compaction.hpp"
 #include "full_collector.hpp"
-#include "callstack.hpp"
 #include "arrays.hpp"
 #include "math.hpp"
 #include "byte_arrays.hpp"
index 6b007f5d420f220c13130dcbd5f582df93dc8c53..a370e3f7129d4447e87c4afbf9ece1d04d00bcd6 100644 (file)
@@ -82,13 +82,13 @@ void factor_vm::primitive_size()
        ctx->push(allot_cell(object_size(ctx->pop())));
 }
 
-struct slot_become_visitor {
+struct slot_become_fixup : no_fixup {
        std::map<object *,object *> *become_map;
 
-       explicit slot_become_visitor(std::map<object *,object *> *become_map_) :
+       explicit slot_become_fixup(std::map<object *,object *> *become_map_) :
                become_map(become_map_) {}
 
-       object *operator()(object *old)
+       object *fixup_data(object *old)
        {
                std::map<object *,object *>::const_iterator iter = become_map->find(old);
                if(iter != become_map->end())
@@ -99,9 +99,9 @@ struct slot_become_visitor {
 };
 
 struct object_become_visitor {
-       slot_visitor<slot_become_visitor> *workhorse;
+       slot_visitor<slot_become_fixup> *workhorse;
 
-       explicit object_become_visitor(slot_visitor<slot_become_visitor> *workhorse_) :
+       explicit object_become_visitor(slot_visitor<slot_become_fixup> *workhorse_) :
                workhorse(workhorse_) {}
 
        void operator()(object *obj)
@@ -111,9 +111,9 @@ struct object_become_visitor {
 };
 
 struct code_block_become_visitor {
-       slot_visitor<slot_become_visitor> *workhorse;
+       slot_visitor<slot_become_fixup> *workhorse;
 
-       explicit code_block_become_visitor(slot_visitor<slot_become_visitor> *workhorse_) :
+       explicit code_block_become_visitor(slot_visitor<slot_become_fixup> *workhorse_) :
                workhorse(workhorse_) {}
 
        void operator()(code_block *compiled, cell size)
@@ -160,7 +160,7 @@ void factor_vm::primitive_become()
 
        /* Update all references to old objects to point to new objects */
        {
-               slot_visitor<slot_become_visitor> workhorse(this,slot_become_visitor(&become_map));
+               slot_visitor<slot_become_fixup> workhorse(this,slot_become_fixup(&become_map));
                workhorse.visit_roots();
                workhorse.visit_contexts();
 
index d4dd44bed1a59b81cc78b5bdc50b04dedfb8ed75..4223f94a570d78e13d33e889de4502c938b5d54b 100644 (file)
@@ -1,6 +1,100 @@
 namespace factor
 {
 
+/* Size of the object pointed to by an untagged pointer */
+template<typename Fixup>
+cell object::size(Fixup fixup) const
+{
+       if(free_p()) return ((free_heap_block *)this)->size();
+
+       switch(type())
+       {
+       case ARRAY_TYPE:
+               return align(array_size((array*)this),data_alignment);
+       case BIGNUM_TYPE:
+               return align(array_size((bignum*)this),data_alignment);
+       case BYTE_ARRAY_TYPE:
+               return align(array_size((byte_array*)this),data_alignment);
+       case STRING_TYPE:
+               return align(string_size(string_capacity((string*)this)),data_alignment);
+       case TUPLE_TYPE:
+               {
+                       tuple_layout *layout = (tuple_layout *)fixup.translate_data(untag<object>(((tuple *)this)->layout));
+                       return align(tuple_size(layout),data_alignment);
+               }
+       case QUOTATION_TYPE:
+               return align(sizeof(quotation),data_alignment);
+       case WORD_TYPE:
+               return align(sizeof(word),data_alignment);
+       case FLOAT_TYPE:
+               return align(sizeof(boxed_float),data_alignment);
+       case DLL_TYPE:
+               return align(sizeof(dll),data_alignment);
+       case ALIEN_TYPE:
+               return align(sizeof(alien),data_alignment);
+       case WRAPPER_TYPE:
+               return align(sizeof(wrapper),data_alignment);
+       case CALLSTACK_TYPE:
+               return align(callstack_object_size(untag_fixnum(((callstack *)this)->length)),data_alignment);
+       default:
+               critical_error("Invalid header in size",(cell)this);
+               return 0; /* can't happen */
+       }
+}
+
+inline cell object::size() const
+{
+       return size(no_fixup());
+}
+
+/* The number of cells from the start of the object which should be scanned by
+the GC. Some types have a binary payload at the end (string, word, DLL) which
+we ignore. */
+template<typename Fixup>
+cell object::binary_payload_start(Fixup fixup) const
+{
+       if(free_p()) return 0;
+
+       switch(type())
+       {
+       /* these objects do not refer to other objects at all */
+       case FLOAT_TYPE:
+       case BYTE_ARRAY_TYPE:
+       case BIGNUM_TYPE:
+       case CALLSTACK_TYPE:
+               return 0;
+       /* these objects have some binary data at the end */
+       case WORD_TYPE:
+               return sizeof(word) - sizeof(cell) * 3;
+       case ALIEN_TYPE:
+               return sizeof(cell) * 3;
+       case DLL_TYPE:
+               return sizeof(cell) * 2;
+       case QUOTATION_TYPE:
+               return sizeof(quotation) - sizeof(cell) * 2;
+       case STRING_TYPE:
+               return sizeof(string);
+       /* everything else consists entirely of pointers */
+       case ARRAY_TYPE:
+               return array_size<array>(array_capacity((array*)this));
+       case TUPLE_TYPE:
+               {
+                       tuple_layout *layout = (tuple_layout *)fixup.translate_data(untag<object>(((tuple *)this)->layout));
+                       return tuple_size(layout);
+               }
+       case WRAPPER_TYPE:
+               return sizeof(wrapper);
+       default:
+               critical_error("Invalid header in binary_payload_start",(cell)this);
+               return 0; /* can't happen */
+       }
+}
+
+inline cell object::binary_payload_start() const
+{
+       return binary_payload_start(no_fixup());
+}
+
 /* Slot visitors iterate over the slots of an object, applying a functor to
 each one that is a non-immediate slot. The pointer is untagged first. The
 functor returns a new untagged object pointer. The return value may or may not equal the old one,
@@ -17,12 +111,12 @@ Iteration is driven by visit_*() methods. Some of them define GC roots:
 - visit_roots()
 - visit_contexts() */
 
-template<typename Visitor> struct slot_visitor {
+template<typename Fixup> struct slot_visitor {
        factor_vm *parent;
-       Visitor visitor;
+       Fixup fixup;
 
-       explicit slot_visitor<Visitor>(factor_vm *parent_, Visitor visitor_) :
-               parent(parent_), visitor(visitor_) {}
+       explicit slot_visitor<Fixup>(factor_vm *parent_, Fixup fixup_) :
+               parent(parent_), fixup(fixup_) {}
 
        cell visit_pointer(cell pointer);
        void visit_handle(cell *handle);
@@ -35,35 +129,36 @@ template<typename Visitor> struct slot_visitor {
        void visit_callback_roots();
        void visit_literal_table_roots();
        void visit_roots();
+       void visit_callstack_object(callstack *stack);
+       void visit_callstack(context *ctx);
        void visit_contexts();
        void visit_code_block_objects(code_block *compiled);
        void visit_embedded_literals(code_block *compiled);
 };
 
-template<typename Visitor>
-cell slot_visitor<Visitor>::visit_pointer(cell pointer)
+template<typename Fixup>
+cell slot_visitor<Fixup>::visit_pointer(cell pointer)
 {
        if(immediate_p(pointer)) return pointer;
 
-       object *untagged = untag<object>(pointer);
-       untagged = visitor(untagged);
+       object *untagged = fixup.fixup_data(untag<object>(pointer));
        return RETAG(untagged,TAG(pointer));
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_handle(cell *handle)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_handle(cell *handle)
 {
        *handle = visit_pointer(*handle);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_object_array(cell *start, cell *end)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_object_array(cell *start, cell *end)
 {
        while(start < end) visit_handle(start++);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_slots(object *ptr, cell payload_start)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_slots(object *ptr, cell payload_start)
 {
        cell *slot = (cell *)ptr;
        cell *end = (cell *)((cell)ptr + payload_start);
@@ -75,20 +170,23 @@ void slot_visitor<Visitor>::visit_slots(object *ptr, cell payload_start)
        }
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_slots(object *ptr)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_slots(object *obj)
 {
-       visit_slots(ptr,ptr->binary_payload_start());
+       if(obj->type() == CALLSTACK_TYPE)
+               visit_callstack_object((callstack *)obj);
+       else
+               visit_slots(obj,obj->binary_payload_start(fixup));
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_stack_elements(segment *region, cell *top)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_stack_elements(segment *region, cell *top)
 {
        visit_object_array((cell *)region->start,top + 1);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_data_roots()
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_data_roots()
 {
        std::vector<data_root_range>::const_iterator iter = parent->data_roots.begin();
        std::vector<data_root_range>::const_iterator end = parent->data_roots.end();
@@ -97,8 +195,8 @@ void slot_visitor<Visitor>::visit_data_roots()
                visit_object_array(iter->start,iter->start + iter->len);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_bignum_roots()
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_bignum_roots()
 {
        std::vector<cell>::const_iterator iter = parent->bignum_roots.begin();
        std::vector<cell>::const_iterator end = parent->bignum_roots.end();
@@ -108,16 +206,16 @@ void slot_visitor<Visitor>::visit_bignum_roots()
                cell *handle = (cell *)(*iter);
 
                if(*handle)
-                       *handle = (cell)visitor(*(object **)handle);
+                       *handle = (cell)fixup.fixup_data(*(object **)handle);
        }
 }
 
-template<typename Visitor>
+template<typename Fixup>
 struct callback_slot_visitor {
        callback_heap *callbacks;
-       slot_visitor<Visitor> *visitor;
+       slot_visitor<Fixup> *visitor;
 
-       explicit callback_slot_visitor(callback_heap *callbacks_, slot_visitor<Visitor> *visitor_) :
+       explicit callback_slot_visitor(callback_heap *callbacks_, slot_visitor<Fixup> *visitor_) :
                callbacks(callbacks_), visitor(visitor_) {}
 
        void operator()(code_block *stub)
@@ -126,15 +224,15 @@ struct callback_slot_visitor {
        }
 };
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_callback_roots()
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_callback_roots()
 {
-       callback_slot_visitor<Visitor> callback_visitor(parent->callbacks,this);
+       callback_slot_visitor<Fixup> callback_visitor(parent->callbacks,this);
        parent->callbacks->each_callback(callback_visitor);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_literal_table_roots()
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_literal_table_roots()
 {
        std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks;
        std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin();
@@ -151,8 +249,8 @@ void slot_visitor<Visitor>::visit_literal_table_roots()
        parent->code->uninitialized_blocks = new_uninitialized_blocks;
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_roots()
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_roots()
 {
        visit_handle(&parent->true_object);
        visit_handle(&parent->bignum_zero);
@@ -167,8 +265,73 @@ void slot_visitor<Visitor>::visit_roots()
        visit_object_array(parent->special_objects,parent->special_objects + special_object_count);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_contexts()
+template<typename Fixup>
+struct call_frame_slot_visitor {
+       factor_vm *parent;
+       slot_visitor<Fixup> *visitor;
+
+       explicit call_frame_slot_visitor(factor_vm *parent_, slot_visitor<Fixup> *visitor_) :
+               parent(parent_), visitor(visitor_) {}
+
+       /*
+       next  -> [entry_point]
+                [size]
+                [return address] -- x86 only, backend adds 1 to each spill location
+                [spill area]
+                ...
+       frame -> [entry_point]
+                [size]
+       */
+       void operator()(stack_frame *frame)
+       {
+               cell return_address = parent->frame_offset(frame);
+               if(return_address == (cell)-1)
+                       return;
+
+               code_block *compiled = visitor->fixup.translate_code(parent->frame_code(frame));
+               gc_info *info = compiled->block_gc_info();
+
+               assert(return_address < compiled->size());
+               int index = info->return_address_index(return_address);
+               if(index == -1)
+                       return;
+
+#ifdef DEBUG_GC_MAPS
+               std::cout << "call frame code block " << compiled << " with offset " << return_address << std::endl;
+#endif
+               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))
+                       {
+#ifdef DEBUG_GC_MAPS
+                               std::cout << "visiting spill slot " << spill_slot << std::endl;
+#endif
+                               visitor->visit_handle(&stack_pointer[spill_slot]);
+                       }
+               }
+       }
+};
+
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_callstack_object(callstack *stack)
+{
+       call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
+       parent->iterate_callstack_object(stack,call_frame_visitor);
+}
+
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_callstack(context *ctx)
+{
+       call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
+       parent->iterate_callstack(ctx,call_frame_visitor);
+}
+
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_contexts()
 {
        std::set<context *>::const_iterator begin = parent->active_contexts.begin();
        std::set<context *>::const_iterator end = parent->active_contexts.end();
@@ -179,16 +342,16 @@ void slot_visitor<Visitor>::visit_contexts()
                visit_stack_elements(ctx->datastack_seg,(cell *)ctx->datastack);
                visit_stack_elements(ctx->retainstack_seg,(cell *)ctx->retainstack);
                visit_object_array(ctx->context_objects,ctx->context_objects + context_object_count);
-
+               visit_callstack(ctx);
                begin++;
        }
 }
 
-template<typename Visitor>
+template<typename Fixup>
 struct literal_references_visitor {
-       slot_visitor<Visitor> *visitor;
+       slot_visitor<Fixup> *visitor;
 
-       explicit literal_references_visitor(slot_visitor<Visitor> *visitor_) : visitor(visitor_) {}
+       explicit literal_references_visitor(slot_visitor<Fixup> *visitor_) : visitor(visitor_) {}
 
        void operator()(instruction_operand op)
        {
@@ -197,20 +360,20 @@ struct literal_references_visitor {
        }
 };
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_code_block_objects(code_block *compiled)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_code_block_objects(code_block *compiled)
 {
        visit_handle(&compiled->owner);
        visit_handle(&compiled->parameters);
        visit_handle(&compiled->relocation);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_embedded_literals(code_block *compiled)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_embedded_literals(code_block *compiled)
 {
        if(!parent->code->uninitialized_p(compiled))
        {
-               literal_references_visitor<Visitor> visitor(this);
+               literal_references_visitor<Fixup> visitor(this);
                compiled->each_instruction_operand(visitor);
        }
 }
index 645e748ea45af82dc102a0462544526f24389dee..147647b5283767fc70795b389ac9028f8ba1744a 100755 (executable)
--- a/vm/vm.hpp
+++ b/vm/vm.hpp
@@ -317,10 +317,11 @@ struct factor_vm
        void collect_compact(bool trace_contexts_p);
        void collect_growing_heap(cell requested_bytes, bool trace_contexts_p);
        void gc(gc_op op, cell requested_bytes, bool trace_contexts_p);
+       void scrub_context(context *ctx);
+       void scrub_contexts();
        void primitive_minor_gc();
        void primitive_full_gc();
        void primitive_compact_gc();
-       void inline_gc(cell gc_roots);
        void primitive_enable_gc_events();
        void primitive_disable_gc_events();
        object *allot_object(cell type, cell size);
@@ -595,6 +596,8 @@ struct factor_vm
        cell frame_executing_quot(stack_frame *frame);
        stack_frame *frame_successor(stack_frame *frame);
        cell frame_scan(stack_frame *frame);
+       cell frame_offset(stack_frame *frame);
+       void set_frame_offset(stack_frame *frame, cell offset);
        void primitive_callstack_to_array();
        stack_frame *innermost_stack_frame(callstack *stack);
        void primitive_innermost_stack_frame_executing();