diff --git a/basis/compiler/cfg/builder/alien/alien.factor b/basis/compiler/cfg/builder/alien/alien.factor
index 7bf45e959a..04ac2bf496 100644
--- a/basis/compiler/cfg/builder/alien/alien.factor
+++ b/basis/compiler/cfg/builder/alien/alien.factor
@@ -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
diff --git a/basis/compiler/cfg/builder/alien/boxing/boxing.factor b/basis/compiler/cfg/builder/alien/boxing/boxing.factor
index 6f5f46b9c1..1992d7539a 100644
--- a/basis/compiler/cfg/builder/alien/boxing/boxing.factor
+++ b/basis/compiler/cfg/builder/alien/boxing/boxing.factor
@@ -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 )
diff --git a/basis/compiler/cfg/finalization/finalization.factor b/basis/compiler/cfg/finalization/finalization.factor
index 5440ba6eef..83bcc0b0b1 100644
--- a/basis/compiler/cfg/finalization/finalization.factor
+++ b/basis/compiler/cfg/finalization/finalization.factor
@@ -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
diff --git a/basis/compiler/cfg/gc-checks/gc-checks-tests.factor b/basis/compiler/cfg/gc-checks/gc-checks-tests.factor
index 698caa5e68..d8745c0784 100644
--- a/basis/compiler/cfg/gc-checks/gc-checks-tests.factor
+++ b/basis/compiler/cfg/gc-checks/gc-checks-tests.factor
@@ -42,13 +42,12 @@ V{
 
 [
     V{
-        T{ ##gc-map f V{ 0 } V{ 3 } { 0 1 2 } }
-        T{ ##call-gc }
+        T{ ##call-gc f T{ gc-map } }
         T{ ##branch }
     }
 ]
 [
-    V{ D 0 R 3 } { 0 1 2 } <gc-call> instructions>>
+    <gc-call> instructions>>
 ] unit-test
 
 30 \ vreg-counter set-global
@@ -82,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
 
@@ -146,8 +145,7 @@ H{
 
 [
     V{
-        T{ ##gc-map f V{ 0 1 2 } V{ } { 2 } }
-        T{ ##call-gc }
+        T{ ##call-gc f T{ gc-map } }
         T{ ##branch }
     }
 ] [ 2 get predecessors>> second instructions>> ] unit-test
diff --git a/basis/compiler/cfg/gc-checks/gc-checks.factor b/basis/compiler/cfg/gc-checks/gc-checks.factor
index 60f81f77d9..50cd67567c 100644
--- a/basis/compiler/cfg/gc-checks/gc-checks.factor
+++ b/basis/compiler/cfg/gc-checks/gc-checks.factor
@@ -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,12 +47,9 @@ IN: compiler.cfg.gc-checks
         ] bi*
     ] V{ } make >>instructions ;
 
-: scrubbed ( uninitialized-locs -- scrub-d scrub-r )
-    [ ds-loc? ] partition [ [ n>> ] map ] bi@ ;
-
-: <gc-call> ( uninitialized-locs gc-roots -- bb )
-    [ <basic-block> ] 2dip
-    [ [ scrubbed ] dip ##gc-map ##call-gc ##branch ] V{ } make
+: <gc-call> ( -- bb )
+    <basic-block>
+    [ <gc-map> ##call-gc ##branch ] V{ } make
     >>instructions t >>unlikely? ;
 
 :: insert-guard ( body check bb -- )
@@ -69,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 )
@@ -85,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 ;
diff --git a/basis/compiler/cfg/instructions/instructions.factor b/basis/compiler/cfg/instructions/instructions.factor
index b46a42d8d5..39d2ab81cd 100644
--- a/basis/compiler/cfg/instructions/instructions.factor
+++ b/basis/compiler/cfg/instructions/instructions.factor
@@ -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,10 +820,7 @@ INSN: ##check-nursery-branch
 literal: size cc
 temp: temp1/int-rep temp2/int-rep ;
 
-INSN: ##call-gc ;
-
-INSN: ##gc-map
-literal: scrub-d scrub-r gc-roots ;
+INSN: ##call-gc literal: gc-map ;
 
 ! Spills and reloads, inserted by register allocator
 TUPLE: spill-slot { n integer } ;
@@ -860,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
diff --git a/basis/compiler/cfg/linear-scan/assignment/assignment.factor b/basis/compiler/cfg/linear-scan/assignment/assignment.factor
index e6d220a90c..cab4438ec9 100644
--- a/basis/compiler/cfg/linear-scan/assignment/assignment.factor
+++ b/basis/compiler/cfg/linear-scan/assignment/assignment.factor
@@ -142,8 +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: ##gc-map assign-registers-in-insn
-    [ [ 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 ;
 
diff --git a/basis/compiler/cfg/liveness/liveness.factor b/basis/compiler/cfg/liveness/liveness.factor
index a10b48cc0c..1a5287355d 100644
--- a/basis/compiler/cfg/liveness/liveness.factor
+++ b/basis/compiler/cfg/liveness/liveness.factor
@@ -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 ;
diff --git a/basis/compiler/cfg/ssa/interference/interference-tests.factor b/basis/compiler/cfg/ssa/interference/interference-tests.factor
index 4e3da1c6dc..36c03bc6af 100644
--- a/basis/compiler/cfg/ssa/interference/interference-tests.factor
+++ b/basis/compiler/cfg/ssa/interference/interference-tests.factor
@@ -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
 
diff --git a/basis/compiler/cfg/stacks/uninitialized/uninitialized-tests.factor b/basis/compiler/cfg/stacks/uninitialized/uninitialized-tests.factor
index 61c3cd67d1..fb9c833136 100644
--- a/basis/compiler/cfg/stacks/uninitialized/uninitialized-tests.factor
+++ b/basis/compiler/cfg/stacks/uninitialized/uninitialized-tests.factor
@@ -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
diff --git a/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor b/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor
index 982e9b872c..7498cddf10 100644
--- a/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor
+++ b/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor
@@ -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 f like
-    ] when ;
diff --git a/basis/compiler/codegen/codegen.factor b/basis/compiler/codegen/codegen.factor
index f33999ab89..68b01beed9 100755
--- a/basis/compiler/codegen/codegen.factor
+++ b/basis/compiler/codegen/codegen.factor
@@ -258,7 +258,6 @@ CODEGEN: ##restore-context %restore-context
 CODEGEN: ##vm-field %vm-field
 CODEGEN: ##set-vm-field %set-vm-field
 CODEGEN: ##alien-global %alien-global
-CODEGEN: ##gc-map %gc-map
 CODEGEN: ##call-gc %call-gc
 CODEGEN: ##spill %spill
 CODEGEN: ##reload %reload
diff --git a/basis/compiler/codegen/fixup/fixup-tests.factor b/basis/compiler/codegen/fixup/fixup-tests.factor
index fcb33e4937..f068861126 100644
--- a/basis/compiler/codegen/fixup/fixup-tests.factor
+++ b/basis/compiler/codegen/fixup/fixup-tests.factor
@@ -1,6 +1,7 @@
 USING: namespaces byte-arrays make compiler.codegen.fixup
 bit-arrays accessors classes.struct tools.test kernel math
-sequences alien.c-types specialized-arrays boxes ;
+sequences alien.c-types specialized-arrays boxes
+compiler.cfg.instructions system cpu.architecture ;
 SPECIALIZED-ARRAY: uint
 IN: compiler.codegen.fixup.tests
 
@@ -10,19 +11,23 @@ STRUCT: gc-info
 { 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> %
 
-        { { } { } { } } set-next-gc-map
-        gc-map-here
+        T{ gc-map f B{ } B{ } V{ } } gc-map-here
 
         50 <byte-array> %
 
-        { { 0 4 } { 1 } { 1 3 } } set-next-gc-map
-        gc-map-here
+        T{ gc-map f B{ 0 1 1 1 0 } B{ 1 0 } V{ 1 3 } } gc-map-here
 
         emit-gc-info
     ] B{ } make
diff --git a/basis/compiler/codegen/fixup/fixup.factor b/basis/compiler/codegen/fixup/fixup.factor
index f0730e91d8..b4ef317b67 100644
--- a/basis/compiler/codegen/fixup/fixup.factor
+++ b/basis/compiler/codegen/fixup/fixup.factor
@@ -4,8 +4,9 @@ USING: arrays bit-arrays byte-arrays byte-vectors generic assocs
 hashtables io.binary kernel kernel.private math namespaces make
 sequences words quotations strings alien.accessors alien.strings
 layouts system combinators math.bitwise math.order
-combinators.smart accessors growable fry compiler.constants
-memoize boxes ;
+combinators.short-circuit combinators.smart accessors growable
+fry memoize compiler.constants compiler.cfg.instructions
+cpu.architecture ;
 IN: compiler.codegen.fixup
 
 ! Utilities
@@ -149,30 +150,37 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ;
 ! uint <largest GC root spill slot>
 ! uint <number of return addresses>
 
-SYMBOLS: next-gc-map return-addresses gc-maps ;
+SYMBOLS: return-addresses gc-maps ;
 
-: gc-map? ( triple -- ? )
+: 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.
-    [ empty? not ] any? ;
+    dup [
+        {
+            [ scrub-d>> empty? ]
+            [ scrub-r>> empty? ]
+            [ gc-roots>> empty? ]
+        } 1&& not
+    ] when ;
 
-: gc-map-here ( -- )
-    next-gc-map get box> dup gc-map? [
+: gc-map-here ( gc-map -- )
+    dup gc-map-needed? [
         gc-maps get push
         compiled-offset return-addresses get push
     ] [ drop ] if ;
 
-: set-next-gc-map ( gc-map -- ) next-gc-map get >box ;
+: 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-bitmap ( seqs -- n )
+: emit-gc-roots ( seqs -- n )
     ! seqs is a sequence of sequences of integers 0..n-1
-    [ 0 ] [
-        dup [ [ 0 ] [ supremum 1 + ] if-empty ] [ max ] map-reduce
-        [ '[ _ integers>bits % ] each ] keep
-    ] if-empty ;
+    dup [ [ 0 ] [ supremum 1 + ] if-empty ] [ max ] map-reduce
+    [ '[ _ integers>bits % ] each ] keep ;
 
 : emit-uint ( n -- )
     building get push-uint ;
@@ -182,9 +190,9 @@ SYMBOLS: next-gc-map return-addresses gc-maps ;
         return-addresses get empty? [ 0 emit-uint ] [
             gc-maps get
             [
-                [ [ first ] map emit-bitmap ]
-                [ [ second ] map emit-bitmap ]
-                [ [ third ] map emit-bitmap ] tri
+                [ [ 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@
@@ -208,12 +216,10 @@ SYMBOLS: next-gc-map return-addresses gc-maps ;
     BV{ } clone relocation-table set
     V{ } clone binary-literal-table set
     V{ } clone return-addresses set
-    V{ } clone gc-maps set
-    <box> next-gc-map set ;
+    V{ } clone gc-maps set ;
 
 : check-fixup ( seq -- )
-    length data-alignment get mod 0 assert=
-    next-gc-map get occupied>> f assert= ;
+    length data-alignment get mod 0 assert= ;
 
 : with-fixup ( quot -- code )
     '[
diff --git a/basis/cpu/architecture/architecture.factor b/basis/cpu/architecture/architecture.factor
index 279947bd43..931dccece1 100644
--- a/basis/cpu/architecture/architecture.factor
+++ b/basis/cpu/architecture/architecture.factor
@@ -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,8 +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: %gc-map cpu ( scrub-d scrub-r gc-roots -- )
-HOOK: %call-gc cpu ( -- )
+HOOK: %call-gc cpu ( gc-map -- )
 
 HOOK: %prologue cpu ( n -- )
 HOOK: %epilogue cpu ( n -- )
@@ -595,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 -- )
 
@@ -609,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 -- )
 
diff --git a/basis/cpu/x86/32/32.factor b/basis/cpu/x86/32/32.factor
index 50835affb0..48cc88a4f8 100755
--- a/basis/cpu/x86/32/32.factor
+++ b/basis/cpu/x86/32/32.factor
@@ -134,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 f %alien-invoke ;
 
 M:: x86.32 %unbox ( dst src func rep -- )
     src func call-unbox-func
@@ -146,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 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 f %alien-invoke ;
 
 M: x86.32 %alien-callback ( quot -- )
     [ EAX ] dip %load-reference
@@ -183,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 f %alien-invoke ;
 
 GENERIC: float-function-param ( n dst src -- )
 
@@ -198,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 f %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 f %alien-invoke
     dst double-rep %load-return ;
 
 : funny-large-struct-return? ( return abi -- ? )
diff --git a/basis/cpu/x86/32/bootstrap.factor b/basis/cpu/x86/32/bootstrap.factor
index 38c98913be..2b82fa8117 100644
--- a/basis/cpu/x86/32/bootstrap.factor
+++ b/basis/cpu/x86/32/bootstrap.factor
@@ -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,9 +256,7 @@ IN: bootstrap.x86
 
 ! Contexts
 : jit-switch-context ( reg -- )
-    ! Dummy return address -- it never gets returned to but it
-    ! must point to inside the current code block
-    ESP -4 [+] HEX: ffffffff MOV rc-absolute-cell rt-this jit-rel
+    -4 jit-scrub-return
 
     ! Save ds, rs registers
     jit-load-vm
diff --git a/basis/cpu/x86/64/64.factor b/basis/cpu/x86/64/64.factor
index 65acdfbeb9..7a5e8a1af3 100644
--- a/basis/cpu/x86/64/64.factor
+++ b/basis/cpu/x86/64/64.factor
@@ -90,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 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 f %alien-invoke ;
 
 M: x86.64 %alien-callback ( quot -- )
     [ param-reg-0 ] dip %load-reference
@@ -121,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 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 f %alien-invoke
     dst double-rep %load-return ;
 
 M:: x86.64 %binary-float-function ( dst src1 src2 func -- )
@@ -136,7 +135,7 @@ 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 f %alien-invoke
     dst double-rep %load-return ;
 
 M: x86.64 long-long-on-stack? f ;
diff --git a/basis/cpu/x86/64/bootstrap.factor b/basis/cpu/x86/64/bootstrap.factor
index 7269e3240f..e81e924245 100644
--- a/basis/cpu/x86/64/bootstrap.factor
+++ b/basis/cpu/x86/64/bootstrap.factor
@@ -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,10 +232,7 @@ IN: bootstrap.x86
 
 ! Contexts
 : jit-switch-context ( reg -- )
-    ! Dummy return address -- it never gets returned to but it
-    ! must point to inside the current code block
-    R11 0 [RIP+] LEA
-    RSP -8 [+] R11 MOV
+    -8 jit-scrub-return
 
     ! Save ds, rs registers
     jit-save-context
diff --git a/basis/cpu/x86/x86.factor b/basis/cpu/x86/x86.factor
index 05251818b5..d3adcf3960 100644
--- a/basis/cpu/x86/x86.factor
+++ b/basis/cpu/x86/x86.factor
@@ -480,13 +480,10 @@ M:: x86 %check-nursery-branch ( label size cc temp1 temp2 -- )
         { cc/<= [ label JG ] }
     } case ;
 
-: gc-root-offsets ( seq -- seq' )
+M: x86 gc-root-offsets
     [ n>> spill-offset special-offset cell + cell /i ] map f like ;
 
-M: x86 %gc-map ( scrub-d scrub-r gc-roots -- )
-    gc-root-offsets 3array set-next-gc-map ;
-
-M: x86 %call-gc
+M: x86 %call-gc ( gc-map -- )
     \ minor-gc %call
     gc-map-here ;
 
@@ -612,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 ;
 
diff --git a/basis/io/sockets/sockets-docs.factor b/basis/io/sockets/sockets-docs.factor
index a41fc1e6c3..d0977dd3d0 100644
--- a/basis/io/sockets/sockets-docs.factor
+++ b/basis/io/sockets/sockets-docs.factor
@@ -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" }
+} ;
diff --git a/basis/math/vectors/simd/cords/cords-tests.factor b/basis/math/vectors/simd/cords/cords-tests.factor
new file mode 100644
index 0000000000..eee11b396a
--- /dev/null
+++ b/basis/math/vectors/simd/cords/cords-tests.factor
@@ -0,0 +1,4 @@
+USING: math.vectors.simd math.vectors.simd.cords tools.test ;
+IN: math.vectors.simd.cords.tests
+
+[ float-4{ 1.0 2.0 3.0 4.0 } ] [ double-4{ 1.0 2.0 3.0 4.0 } >float-4 ] unit-test
diff --git a/basis/math/vectors/simd/cords/cords.factor b/basis/math/vectors/simd/cords/cords.factor
index 4d98af538f..cc3aa023e7 100644
--- a/basis/math/vectors/simd/cords/cords.factor
+++ b/basis/math/vectors/simd/cords/cords.factor
@@ -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
diff --git a/basis/prettyprint/backend/backend.factor b/basis/prettyprint/backend/backend.factor
index 7d0cb40576..201a1c28d2 100644
--- a/basis/prettyprint/backend/backend.factor
+++ b/basis/prettyprint/backend/backend.factor
@@ -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 ;
diff --git a/basis/sequences/cords/cords.factor b/basis/sequences/cords/cords.factor
index 5be500abd4..766fbe87c0 100644
--- a/basis/sequences/cords/cords.factor
+++ b/basis/sequences/cords/cords.factor
@@ -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
diff --git a/basis/tools/disassembler/udis/udis-tests.factor b/basis/tools/disassembler/udis/udis-tests.factor
index df3ef41365..522893f368 100644
--- a/basis/tools/disassembler/udis/udis-tests.factor
+++ b/basis/tools/disassembler/udis/udis-tests.factor
@@ -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
diff --git a/basis/tools/disassembler/udis/udis.factor b/basis/tools/disassembler/udis/udis.factor
index e998a5cfdb..8cf885f583 100644
--- a/basis/tools/disassembler/udis/udis.factor
+++ b/basis/tools/disassembler/udis/udis.factor
@@ -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 ) ;
diff --git a/basis/typed/prettyprint/prettyprint.factor b/basis/typed/prettyprint/prettyprint.factor
index 8a7ff5b7b2..4bb8814e4c 100644
--- a/basis/typed/prettyprint/prettyprint.factor
+++ b/basis/typed/prettyprint/prettyprint.factor
@@ -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 ;
diff --git a/basis/typed/typed-tests.factor b/basis/typed/typed-tests.factor
index bca1136ee6..70edcf2334 100644
--- a/basis/typed/typed-tests.factor
+++ b/basis/typed/typed-tests.factor
@@ -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 + ;
diff --git a/basis/typed/typed.factor b/basis/typed/typed.factor
index 50da7b1bad..fe2ba41722 100644
--- a/basis/typed/typed.factor
+++ b/basis/typed/typed.factor
@@ -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 ;
 
diff --git a/core/vocabs/loader/loader-docs.factor b/core/vocabs/loader/loader-docs.factor
index 423abbc277..d3736db9bf 100755
--- a/core/vocabs/loader/loader-docs.factor
+++ b/core/vocabs/loader/loader-docs.factor
@@ -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
index 0000000000..f13c9c1e77
--- /dev/null
+++ b/extra/alien/handles/authors.txt
@@ -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
index 0000000000..38ce7c26c7
--- /dev/null
+++ b/extra/alien/handles/handles-tests.factor
@@ -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
index 0000000000..e1b5a716d2
--- /dev/null
+++ b/extra/alien/handles/handles.factor
@@ -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
index 0000000000..17c2a240cd
--- /dev/null
+++ b/extra/alien/handles/summary.txt
@@ -0,0 +1 @@
+Generate integer handle values to allow Factor object references to be passed through the FFI
diff --git a/extra/bson/constants/constants.factor b/extra/bson/constants/constants.factor
index 2d126857c3..e4bf14432a 100644
--- a/extra/bson/constants/constants.factor
+++ b/extra/bson/constants/constants.factor
@@ -19,6 +19,16 @@ TUPLE: oid { a initial: 0 } { b initial: 0 } ;
 
 TUPLE: dbref ref id db ;
 
+TUPLE: mongo-timestamp incr seconds ;
+
+: <mongo-timestamp> ( incr seconds -- mongo-timestamp )
+    mongo-timestamp boa ;
+
+TUPLE: mongo-scoped-code code object ;
+
+: <mongo-scoped-code> ( code object -- mongo-scoped-code )
+    mongo-scoped-code boa ;
+
 CONSTRUCTOR: dbref ( ref id -- dbref ) ;
 
 : dbref>assoc ( dbref -- assoc )
@@ -47,30 +57,31 @@ TUPLE: mdbregexp { regexp string } { options string } ;
 CONSTANT: MDB_OID_FIELD "_id"
 CONSTANT: MDB_META_FIELD "_mfd"
 
-CONSTANT: T_EOO  0  
-CONSTANT: T_Double  1  
-CONSTANT: T_Integer  16  
-CONSTANT: T_Boolean  8  
-CONSTANT: T_String  2  
-CONSTANT: T_Object  3  
-CONSTANT: T_Array  4  
-CONSTANT: T_Binary  5  
-CONSTANT: T_Undefined  6  
-CONSTANT: T_OID  7  
-CONSTANT: T_Date  9  
-CONSTANT: T_NULL  10  
-CONSTANT: T_Regexp  11  
-CONSTANT: T_DBRef  12  
-CONSTANT: T_Code  13  
-CONSTANT: T_ScopedCode  17  
-CONSTANT: T_Symbol  14  
-CONSTANT: T_JSTypeMax  16  
-CONSTANT: T_MaxKey  127  
-
-CONSTANT: T_Binary_Function 1   
-CONSTANT: T_Binary_Bytes 2
-CONSTANT: T_Binary_UUID 3
-CONSTANT: T_Binary_MD5 5
-CONSTANT: T_Binary_Custom 128
+CONSTANT: T_EOO     0
+CONSTANT: T_Double  HEX: 1
+CONSTANT: T_String  HEX: 2
+CONSTANT: T_Object  HEX: 3
+CONSTANT: T_Array   HEX: 4
+CONSTANT: T_Binary  HEX: 5
+CONSTANT: T_Undefined  HEX: 6
+CONSTANT: T_OID     HEX: 7
+CONSTANT: T_Boolean HEX: 8
+CONSTANT: T_Date    HEX: 9
+CONSTANT: T_NULL    HEX: A
+CONSTANT: T_Regexp  HEX: B
+CONSTANT: T_DBRef   HEX: C
+CONSTANT: T_Code    HEX: D
+CONSTANT: T_Symbol  HEX: E
+CONSTANT: T_ScopedCode HEX: F
+CONSTANT: T_Integer HEX: 10
+CONSTANT: T_Timestamp HEX: 11
+CONSTANT: T_Integer64 HEX: 12
+CONSTANT: T_MinKey  HEX: FF
+CONSTANT: T_MaxKey  HEX: 7F
 
+CONSTANT: T_Binary_Function     HEX: 1
+CONSTANT: T_Binary_Bytes        HEX: 2
+CONSTANT: T_Binary_UUID         HEX: 3
+CONSTANT: T_Binary_MD5          HEX: 5
+CONSTANT: T_Binary_Custom       HEX: 80
 
diff --git a/extra/bson/reader/reader.factor b/extra/bson/reader/reader.factor
index e0cf0bc4f4..852f46f951 100644
--- a/extra/bson/reader/reader.factor
+++ b/extra/bson/reader/reader.factor
@@ -10,65 +10,46 @@ FROM: typed => TYPED: ;
 
 IN: bson.reader
 
+SYMBOL: state
+
+DEFER: stream>assoc
+
 <PRIVATE
 
-TUPLE: element { type integer } name ;
+DEFER: read-elements
 
-TUPLE: state
-    { size initial: -1 }
-    { exemplar assoc }
-    result
-    { scope vector }
-    { elements vector } ;
-
-TYPED: (prepare-elements) ( -- elements-vector: vector )
-    V{ } clone [ T_Object "" element boa swap push ] [ ] bi ; inline
-
-: <state> ( exemplar -- state )
-    [ state new ] dip
-    {
-        [ clone >>exemplar ]
-        [ clone >>result ]
-        [ V{ } clone [ push ] keep >>scope ]
-    } cleave
-    (prepare-elements) >>elements ;
-
-TYPED: get-state ( -- state: state )
-    state get ; inline
-
-TYPED: read-int32 ( -- int32: integer )
+: read-int32 ( -- int32 )
     4 read signed-le> ; inline
 
-TYPED: read-longlong ( -- longlong: integer )
+: read-longlong ( -- longlong )
     8 read signed-le> ; inline
 
-TYPED: read-double ( -- double: float )
+: read-double ( -- double )
     8 read le> bits>double ; inline
 
-TYPED: read-byte-raw ( -- byte-raw: byte-array )
+: read-byte-raw ( -- byte-raw )
     1 read ; inline
 
-TYPED: read-byte ( -- byte: integer )
+: read-byte ( -- byte )
     read-byte-raw first ; inline
 
-TYPED: read-cstring ( -- string: string )
+: read-cstring ( -- string )
     "\0" read-until drop >string ; inline
 
-TYPED: read-sized-string ( length: integer -- string: string )
+: read-sized-string ( length -- string )
     read 1 head-slice* >string ; inline
 
-TYPED: push-element ( type: integer name: string state: state -- )
-    [ element boa ] dip elements>> push ; inline
+: read-timestamp ( -- timestamp )
+    8 read [ 4 head signed-le> ] [ 4 tail signed-le> ] bi <mongo-timestamp> ;
 
-TYPED: pop-element ( state: state -- element: element )
-    elements>> pop ; inline
+: object-result ( quot -- object )
+    [
+        state get clone
+        [ clear-assoc ] [ ] [ ] tri state
+    ] dip with-variable ; inline
 
-TYPED: peek-scope ( state: state -- ht )
-    scope>> last ; inline
-
-: bson-object-data-read ( -- object )
-    read-int32 drop get-state 
-    [ exemplar>> clone dup ] [ scope>> ] bi push ; inline
+: bson-object-data-read ( -- )
+    read-int32 drop read-elements ; inline recursive
 
 : bson-binary-read ( -- binary )
    read-int32 read-byte 
@@ -86,68 +67,35 @@ TYPED: bson-regexp-read ( -- mdbregexp: mdbregexp )
 TYPED: bson-oid-read ( -- oid: oid )
     read-longlong read-int32 oid boa ; inline
 
-TYPED: element-data-read ( type: integer -- object )
-    {
-        { T_OID [ bson-oid-read ] }
-        { T_String [ read-int32 read-sized-string ] }
-        { T_Integer [ read-int32 ] }
-        { T_Binary [ bson-binary-read ] }
-        { T_Object [ bson-object-data-read ] }
-        { T_Array [ bson-object-data-read ] }
-        { T_Double [ read-double ] }
-        { T_Boolean [ read-byte 1 = ] }
-        { T_Date [ read-longlong millis>timestamp ] }
-        { T_Regexp [ bson-regexp-read ] }
-        { T_NULL [ f ] }
-    } case ; inline
-
-TYPED: bson-array? ( type: integer -- ?: boolean )
-    T_Array = ; inline
-
-TYPED: bson-object? ( type: integer -- ?: boolean )
-    T_Object = ; inline
-
 : check-object ( assoc -- object )
     dup dbref-assoc? [ assoc>dbref ] when ; inline
 
-TYPED: fix-result ( assoc type: integer -- result )
+TYPED: element-data-read ( type: integer -- object )
     {
-        { T_Array [ values ] }
-        { T_Object [ check-object ] }
-    } case ; inline
+        { T_OID         [ bson-oid-read ] }
+        { T_String      [ read-int32 read-sized-string ] }
+        { T_Integer     [ read-int32 ] }
+        { T_Integer64   [ read-longlong ] }
+        { T_Binary      [ bson-binary-read ] }
+        { T_Object      [ [ bson-object-data-read ] object-result check-object ] }
+        { T_Array       [ [ bson-object-data-read ] object-result values ] }
+        { T_Double      [ read-double ] }
+        { T_Boolean     [ read-byte 1 = ] }
+        { T_Date        [ read-longlong millis>timestamp ] }
+        { T_Regexp      [ bson-regexp-read ] }
+        { T_Timestamp   [ read-timestamp ] }
+        { T_Code        [ read-int32 read-sized-string ] }
+        { T_ScopedCode  [ read-int32 drop read-cstring H{ } clone stream>assoc <mongo-scoped-code> ] }
+        { T_NULL        [ f ] }
+    } case ; inline recursive
 
-TYPED: end-element ( type: integer -- )
-    { [ bson-object? ] [ bson-array? ] } 1||
-    [ get-state pop-element drop ] unless ; inline
-
-TYPED: (>state<) ( -- state: state scope: vector element: element )
-    get-state [  ] [ scope>> ] [ pop-element ] tri ; inline
-
-TYPED: (prepare-result) ( scope: vector element: element -- result )
-    [ pop ] [ type>> ] bi* fix-result ; inline
-
-: bson-eoo-element-read ( -- cont?: boolean )
-    (>state<)
-    [ (prepare-result) ] [  ] [ drop empty? ] 2tri
-    [ 2drop >>result drop f ]
-    [ swap [ name>> ] [ last ] bi* set-at drop t ] if ; inline
-
-TYPED: (prepare-object) ( type: integer -- object )
-    [ element-data-read ] [ end-element ] bi ; inline
-
-:: (read-object) ( type name state -- )
-    state peek-scope :> scope
-    type (prepare-object) name scope set-at ; inline
-
-TYPED: bson-not-eoo-element-read ( type: integer -- cont?: boolean )
-    read-cstring get-state
-    [ push-element ]
-    [ (read-object) t ] 3bi ; inline
+TYPED: (read-object) ( type: integer name: string -- )
+    [ element-data-read ] dip state get set-at ; inline recursive
 
 TYPED: (element-read) ( type: integer -- cont?: boolean )
     dup T_EOO > 
-    [ bson-not-eoo-element-read ]
-    [ drop bson-eoo-element-read ] if ; inline
+    [ read-cstring (read-object) t ]
+    [ drop f ] if ; inline recursive
 
 : read-elements ( -- )
     read-byte (element-read)
@@ -156,6 +104,6 @@ TYPED: (element-read) ( type: integer -- cont?: boolean )
 PRIVATE>
 
 : stream>assoc ( exemplar -- assoc )
-    <state> read-int32 >>size
-    [ state [ read-elements ] with-variable ]
-    [ result>> ] bi ;
+    clone [
+        state [ bson-object-data-read ] with-variable
+    ] keep ;
diff --git a/extra/opengl/glu/glu.factor b/extra/opengl/glu/glu.factor
index 856740d229..678e780e60 100644
--- a/extra/opengl/glu/glu.factor
+++ b/extra/opengl/glu/glu.factor
@@ -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 ;
diff --git a/extra/pop3/pop3-tests.factor b/extra/pop3/pop3-tests.factor
index 8efc07ceee..10c5024d58 100644
--- a/extra/pop3/pop3-tests.factor
+++ b/extra/pop3/pop3-tests.factor
@@ -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
diff --git a/misc/fuel/fuel-font-lock.el b/misc/fuel/fuel-font-lock.el
index 8d3990fcd8..d54b0cd337 100644
--- a/misc/fuel/fuel-font-lock.el
+++ b/misc/fuel/fuel-font-lock.el
@@ -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)")
@@ -101,6 +102,9 @@
     (,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)
@@ -111,6 +115,11 @@
     (,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)
@@ -124,6 +133,7 @@
     (,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)
diff --git a/misc/fuel/fuel-syntax.el b/misc/fuel/fuel-syntax.el
index 80010235b1..e2db30db3d 100644
--- a/misc/fuel/fuel-syntax.el
+++ b/misc/fuel/fuel-syntax.el
@@ -47,10 +47,10 @@
   '(":" "::" ";" "&:" "<<" "<PRIVATE" ">>"
     "ABOUT:" "AFTER:" "ALIAS:" "ALIEN:" "ARTICLE:"
     "B" "BEFORE:" "BIN:"
-    "C:" "CALLBACK:" "ENUM:" "C-TYPE:" "CHAR:" "COM-INTERFACE:" "CONSTANT:" "CONSULT:" "call-next-method"
-    "DEFER:"
-    "EBNF:" ";EBNF" "ERROR:" "EXCLUDE:"
-    "f" "FORGET:" "FROM:" "FUNCTION:"
+    "C:" "CALLBACK:" "C-GLOBAL:" "C-TYPE:" "CHAR:" "COM-INTERFACE:" "CONSTANT:" "CONSULT:" "call-next-method"
+    "DEFER:" "DESTRUCTOR:"
+    "EBNF:" ";EBNF" "ENUM:" "ERROR:" "EXCLUDE:"
+    "f" "FORGET:" "FROM:" "FUNCTION:" "FUNCTION-ALIAS:"
     "GAME:" "GENERIC#" "GENERIC:"
     "GLSL-SHADER:" "GLSL-PROGRAM:"
     "HELP:" "HEX:" "HOOK:"
@@ -135,6 +135,9 @@
   (fuel-syntax--second-word-regex
    '("C-STRUCT:" "C-UNION:" "COM-INTERFACE:" "MIXIN:" "TUPLE:" "SINGLETON:" "SPECIALIZED-ARRAY:" "STRUCT:" "UNION:" "UNION-STRUCT:")))
 
+(defconst fuel-syntax--error-regex
+  (fuel-syntax--second-word-regex '("ERROR:")))
+
 (defconst fuel-syntax--tuple-decl-regex
   "^TUPLE: +\\([^ \n]+\\) +< +\\([^ \n]+\\)\\_>")
 
@@ -158,15 +161,19 @@
 (defconst fuel-syntax--sub-vocab-regex "^<\\([^ \n]+\\) *$")
 
 (defconst fuel-syntax--alien-function-regex
-  "\\_<FUNCTION: \\(\\w+\\) \\(\\w+\\)")
+  "\\_<FUNCTION: +\\(\\w+\\)[\n ]+\\(\\w+\\)")
+
+(defconst fuel-syntax--alien-function-alias-regex
+  "\\_<FUNCTION-ALIAS: +\\(\\w+\\)[\n ]+\\(\\w+\\)[\n ]+\\(\\w+\\)")
 
 (defconst fuel-syntax--alien-callback-regex
-  "\\_<CALLBACK: \\(\\w+\\) \\(\\w+\\)")
+  "\\_<CALLBACK: +\\(\\w+\\) +\\(\\w+\\)")
 
 (defconst fuel-syntax--indent-def-starts '("" ":"
                                            "AFTER" "BEFORE"
-                                           "ENUM" "COM-INTERFACE" "CONSULT"
-                                           "FROM" "FUNCTION:"
+                                           "COM-INTERFACE" "CONSULT"
+                                           "ENUM" "ERROR"
+                                           "FROM" "FUNCTION:" "FUNCTION-ALIAS:"
                                            "INTERSECTION:"
                                            "M" "M:" "MACRO" "MACRO:"
                                            "MEMO" "MEMO:" "METHOD"
@@ -197,10 +204,10 @@
 (defconst fuel-syntax--single-liner-regex
   (regexp-opt '("ABOUT:"
                 "ALIAS:"
-                "CONSTANT:" "C:" "C-TYPE:"
-                "DEFER:"
+                "CONSTANT:" "C:" "C-GLOBAL:" "C-TYPE:"
+                "DEFER:" "DESTRUCTOR:"
                 "FORGET:"
-                "GAME:" "GENERIC:" "GENERIC#" "GLSL-PROGRAM:" 
+                "GAME:" "GENERIC:" "GENERIC#" "GLSL-PROGRAM:"
                 "HEX:" "HOOK:"
                 "IN:" "INSTANCE:"
                 "LIBRARY:"
@@ -242,6 +249,12 @@
 (defconst fuel-syntax--typedef-regex
   "\\_<TYPEDEF: +\\(\\w+\\) +\\(\\w+\\)\\( .*\\)?$")
 
+(defconst fuel-syntax--c-global-regex
+  "\\_<C-GLOBAL: +\\(\\w+\\) +\\(\\w+\\)\\( .*\\)?$")
+
+(defconst fuel-syntax--c-type-regex
+  "\\_<C-TYPE: +\\(\\w+\\)\\( .*\\)?$")
+
 (defconst fuel-syntax--rename-regex
   "\\_<RENAME: +\\(\\w+\\) +\\(\\w+\\) +=> +\\(\\w+\\)\\( .*\\)?$")
 
diff --git a/vm/callstack.cpp b/vm/callstack.cpp
index dd76714245..64c17d8661 100755
--- a/vm/callstack.cpp
+++ b/vm/callstack.cpp
@@ -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,11 +150,6 @@ cell factor_vm::frame_scan(stack_frame *frame)
 	}
 }
 
-cell factor_vm::frame_offset(stack_frame *frame)
-{
-	return (cell)FRAME_RETURN_ADDRESS(frame,this) - (cell)frame_code(frame)->entry_point();
-}
-
 struct stack_frame_accumulator {
 	factor_vm *parent;
 	growable_array frames;
@@ -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()
diff --git a/vm/code_block_visitor.hpp b/vm/code_block_visitor.hpp
index b6581b8c8f..8b48d3672f 100644
--- a/vm/code_block_visitor.hpp
+++ b/vm/code_block_visitor.hpp
@@ -42,13 +42,10 @@ struct call_frame_code_block_visitor {
 
 	void operator()(stack_frame *frame)
 	{
-		code_block *old_block = parent->frame_code(frame);
-		cell offset = (char *)FRAME_RETURN_ADDRESS(frame,parent) - (char *)old_block;
-
-		const code_block *new_block = fixup.fixup_code(old_block);
-		frame->entry_point = new_block->entry_point();
-
-		FRAME_RETURN_ADDRESS(frame,parent) = (char *)new_block + 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);
 	}
 };
 
diff --git a/vm/collector.hpp b/vm/collector.hpp
index 400e15b974..4a9eec5967 100644
--- a/vm/collector.hpp
+++ b/vm/collector.hpp
@@ -43,6 +43,8 @@ template<typename TargetGeneration, typename Policy> struct gc_workhorse : no_fi
 
 	object *fixup_data(object *obj)
 	{
+		parent->check_data_pointer(obj);
+
 		if(!policy.should_copy_p(obj))
 		{
 			policy.visited_object(obj);
diff --git a/vm/contexts.cpp b/vm/contexts.cpp
index 6247b879c6..8ec3363662 100644
--- a/vm/contexts.cpp
+++ b/vm/contexts.cpp
@@ -65,7 +65,12 @@ void context::scrub_stacks(gc_info *info, cell 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;
+			}
 		}
 	}
 
@@ -75,7 +80,12 @@ void context::scrub_stacks(gc_info *info, cell 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;
+			}
 		}
 	}
 }
diff --git a/vm/free_list_allocator.hpp b/vm/free_list_allocator.hpp
index 7d7807ef9a..8c63bd487d 100644
--- a/vm/free_list_allocator.hpp
+++ b/vm/free_list_allocator.hpp
@@ -164,7 +164,7 @@ template<typename Block, typename Iterator> struct heap_compactor {
 	{
 		if(this->state->marked_p(block))
 		{
-			*finger = block;
+			*finger = (Block *)((char *)block + size);
 			memmove((Block *)address,block,size);
 			iter(block,(Block *)address,size);
 			address += size;
diff --git a/vm/gc.cpp b/vm/gc.cpp
index 24f773b226..766940a2d7 100755
--- a/vm/gc.cpp
+++ b/vm/gc.cpp
@@ -207,13 +207,15 @@ struct call_frame_scrubber {
 
 	void operator()(stack_frame *frame)
 	{
-		const code_block *compiled = parent->frame_code(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();
 
-		cell return_address = parent->frame_offset(frame);
 		assert(return_address < compiled->size());
 		int index = info->return_address_index(return_address);
-
 		if(index != -1)
 			ctx->scrub_stacks(info,index);
 	}
diff --git a/vm/slot_visitor.hpp b/vm/slot_visitor.hpp
index 8d1c27a55c..4223f94a57 100644
--- a/vm/slot_visitor.hpp
+++ b/vm/slot_visitor.hpp
@@ -284,22 +284,33 @@ struct call_frame_slot_visitor {
 	*/
 	void operator()(stack_frame *frame)
 	{
-		const code_block *compiled = visitor->fixup.translate_code(parent->frame_code(frame));
-		gc_info *info = compiled->block_gc_info();
 		cell return_address = parent->frame_offset(frame);
+		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;
 
-		if(index != -1)
+#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++)
 		{
-			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))
 			{
-				if(bitmap_p(bitmap,base + spill_slot))
-					visitor->visit_handle(&stack_pointer[spill_slot]);
+#ifdef DEBUG_GC_MAPS
+				std::cout << "visiting spill slot " << spill_slot << std::endl;
+#endif
+				visitor->visit_handle(&stack_pointer[spill_slot]);
 			}
 		}
 	}
diff --git a/vm/vm.hpp b/vm/vm.hpp
index 5c2b0697f7..147647b528 100755
--- a/vm/vm.hpp
+++ b/vm/vm.hpp
@@ -597,6 +597,7 @@ struct factor_vm
 	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();