From 99216b8435d2d462773336804c7ab995e9b1211d Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 30 Jul 2009 09:19:44 -0500 Subject: [PATCH] compiler.cfg: Get inline GC checks working again, using a dataflow analysis to compute uninitialized stack locations in compiler.cfg.stacks.uninitialized. Re-enable intrinsics which use inline allocation --- .../cfg/gc-checks/gc-checks-tests.factor | 26 +++++++ basis/compiler/cfg/gc-checks/gc-checks.factor | 28 ++++--- .../cfg/instructions/instructions.factor | 4 +- .../compiler/cfg/intrinsics/intrinsics.factor | 14 ++-- .../cfg/linearization/linearization.factor | 21 ++--- .../uninitialized/uninitialized-tests.factor | 61 +++++++++++++++ .../stacks/uninitialized/uninitialized.factor | 76 +++++++++++++++++++ basis/compiler/codegen/codegen.factor | 1 + basis/cpu/architecture/architecture.factor | 2 +- basis/cpu/x86/x86.factor | 7 +- 10 files changed, 211 insertions(+), 29 deletions(-) create mode 100644 basis/compiler/cfg/gc-checks/gc-checks-tests.factor create mode 100644 basis/compiler/cfg/stacks/uninitialized/uninitialized-tests.factor create mode 100644 basis/compiler/cfg/stacks/uninitialized/uninitialized.factor diff --git a/basis/compiler/cfg/gc-checks/gc-checks-tests.factor b/basis/compiler/cfg/gc-checks/gc-checks-tests.factor new file mode 100644 index 0000000000..7b3e07faf8 --- /dev/null +++ b/basis/compiler/cfg/gc-checks/gc-checks-tests.factor @@ -0,0 +1,26 @@ +IN: compiler.cfg.gc-checks.tests +USING: compiler.cfg.gc-checks compiler.cfg.debugger +compiler.cfg.registers compiler.cfg.instructions compiler.cfg +compiler.cfg.predecessors cpu.architecture tools.test kernel vectors +namespaces accessors sequences ; + +: test-gc-checks ( -- ) + cfg new 0 get >>entry + compute-predecessors + insert-gc-checks + drop ; + +V{ + T{ ##inc-d f 3 } + T{ ##replace f V int-regs 0 D 1 } +} 0 test-bb + +V{ + T{ ##box-float f V int-regs 0 V int-regs 1 } +} 1 test-bb + +0 get 1 get 1vector >>successors drop + +[ ] [ test-gc-checks ] unit-test + +[ V{ D 0 D 2 } ] [ 1 get instructions>> first uninitialized-locs>> ] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/gc-checks/gc-checks.factor b/basis/compiler/cfg/gc-checks/gc-checks.factor index 8435a231e6..c34f2c42a3 100644 --- a/basis/compiler/cfg/gc-checks/gc-checks.factor +++ b/basis/compiler/cfg/gc-checks/gc-checks.factor @@ -1,17 +1,27 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors kernel sequences assocs -compiler.cfg.rpo compiler.cfg.instructions -compiler.cfg.hats ; +USING: accessors kernel sequences assocs fry +compiler.cfg.rpo +compiler.cfg.hats +compiler.cfg.registers +compiler.cfg.instructions +compiler.cfg.stacks.uninitialized ; IN: compiler.cfg.gc-checks -: gc? ( bb -- ? ) +: insert-gc-check? ( bb -- ? ) instructions>> [ ##allocation? ] any? ; -: insert-gc-check ( basic-block -- ) - dup gc? [ - [ i i f \ ##gc new-insn prefix ] change-instructions drop - ] [ drop ] if ; +: blocks-with-gc ( cfg -- bbs ) + post-order [ insert-gc-check? ] filter ; + +: insert-gc-check ( bb -- ) + dup '[ + i i f _ uninitialized-locs \ ##gc new-insn + prefix + ] change-instructions drop ; : insert-gc-checks ( cfg -- cfg' ) - dup [ insert-gc-check ] each-basic-block ; \ No newline at end of file + dup blocks-with-gc [ + over compute-uninitialized-sets + [ insert-gc-check ] each + ] unless-empty ; \ No newline at end of file diff --git a/basis/compiler/cfg/instructions/instructions.factor b/basis/compiler/cfg/instructions/instructions.factor index e08b3b25bb..0a52f1aa94 100644 --- a/basis/compiler/cfg/instructions/instructions.factor +++ b/basis/compiler/cfg/instructions/instructions.factor @@ -190,7 +190,7 @@ INSN: ##fixnum-add < ##fixnum-overflow ; INSN: ##fixnum-sub < ##fixnum-overflow ; INSN: ##fixnum-mul < ##fixnum-overflow ; -INSN: ##gc temp1 temp2 live-values ; +INSN: ##gc temp1 temp2 live-values uninitialized-locs ; ! Instructions used by machine IR only. INSN: _prologue stack-frame ; @@ -219,7 +219,7 @@ INSN: _fixnum-mul < _fixnum-overflow ; TUPLE: spill-slot n ; C: spill-slot -INSN: _gc temp1 temp2 gc-roots gc-root-count gc-root-size ; +INSN: _gc temp1 temp2 gc-roots gc-root-count gc-root-size uninitialized-locs ; ! These instructions operate on machine registers and not ! virtual registers diff --git a/basis/compiler/cfg/intrinsics/intrinsics.factor b/basis/compiler/cfg/intrinsics/intrinsics.factor index c6642d8ad9..2618db0904 100644 --- a/basis/compiler/cfg/intrinsics/intrinsics.factor +++ b/basis/compiler/cfg/intrinsics/intrinsics.factor @@ -48,11 +48,11 @@ IN: compiler.cfg.intrinsics slots.private:set-slot strings.private:string-nth strings.private:set-string-nth-fast - ! classes.tuple.private: - ! arrays: - ! byte-arrays: - ! byte-arrays:(byte-array) - ! kernel: + classes.tuple.private: + arrays: + byte-arrays: + byte-arrays:(byte-array) + kernel: alien.accessors:alien-unsigned-1 alien.accessors:set-alien-unsigned-1 alien.accessors:alien-signed-1 @@ -61,7 +61,7 @@ IN: compiler.cfg.intrinsics alien.accessors:set-alien-unsigned-2 alien.accessors:alien-signed-2 alien.accessors:set-alien-signed-2 - ! alien.accessors:alien-cell + alien.accessors:alien-cell alien.accessors:set-alien-cell } [ t "intrinsic" set-word-prop ] each @@ -90,7 +90,7 @@ IN: compiler.cfg.intrinsics alien.accessors:set-alien-float alien.accessors:alien-double alien.accessors:set-alien-double - } drop f [ t "intrinsic" set-word-prop ] each ; + } [ t "intrinsic" set-word-prop ] each ; : enable-fixnum-log2 ( -- ) \ math.integers.private:fixnum-log2 t "intrinsic" set-word-prop ; diff --git a/basis/compiler/cfg/linearization/linearization.factor b/basis/compiler/cfg/linearization/linearization.factor index 97fb3205c2..cbeb301901 100755 --- a/basis/compiler/cfg/linearization/linearization.factor +++ b/basis/compiler/cfg/linearization/linearization.factor @@ -98,15 +98,18 @@ M: ##dispatch linearize-insn M: ##gc linearize-insn nip - [ temp1>> ] - [ temp2>> ] - [ - live-values>> - [ compute-gc-roots ] - [ count-gc-roots ] - [ gc-roots-size ] - tri - ] tri + { + [ temp1>> ] + [ temp2>> ] + [ + live-values>> + [ compute-gc-roots ] + [ count-gc-roots ] + [ gc-roots-size ] + tri + ] + [ uninitialized-locs>> ] + } cleave _gc ; : linearize-basic-blocks ( cfg -- insns ) diff --git a/basis/compiler/cfg/stacks/uninitialized/uninitialized-tests.factor b/basis/compiler/cfg/stacks/uninitialized/uninitialized-tests.factor new file mode 100644 index 0000000000..6f3e35994a --- /dev/null +++ b/basis/compiler/cfg/stacks/uninitialized/uninitialized-tests.factor @@ -0,0 +1,61 @@ +IN: compiler.cfg.stacks.uninitialized.tests +USING: compiler.cfg.stacks.uninitialized compiler.cfg.debugger +compiler.cfg.registers compiler.cfg.instructions compiler.cfg +compiler.cfg.predecessors cpu.architecture tools.test kernel vectors +namespaces accessors sequences ; + +: test-uninitialized ( -- ) + cfg new 0 get >>entry + compute-predecessors + compute-uninitialized-sets ; + +V{ + T{ ##inc-d f 3 } +} 0 test-bb + +V{ + T{ ##replace f V int-regs 0 D 0 } + T{ ##replace f V int-regs 0 D 1 } + T{ ##replace f V int-regs 0 D 2 } + T{ ##inc-r f 1 } +} 1 test-bb + +V{ + T{ ##peek f V int-regs 0 D 0 } + T{ ##inc-d f 1 } +} 2 test-bb + +0 get 1 get 1vector >>successors drop +1 get 2 get 1vector >>successors drop + +[ ] [ 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 + +! When merging, if a location is uninitialized in one branch and +! initialized in another, we have to consider it uninitialized, +! since it cannot be safely read from by a ##peek, or traced by GC. + +V{ } 0 test-bb + +V{ + T{ ##inc-d f 1 } +} 1 test-bb + +V{ + T{ ##call f namestack } + T{ ##branch } +} 2 test-bb + +V{ + T{ ##return } +} 3 test-bb + +0 get 1 get 2 get V{ } 2sequence >>successors drop +1 get 3 get 1vector >>successors drop +2 get 3 get 1vector >>successors drop + +[ ] [ test-uninitialized ] unit-test + +[ V{ D 0 } ] [ 3 get uninitialized-locs ] unit-test diff --git a/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor b/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor new file mode 100644 index 0000000000..ee60c4bd7a --- /dev/null +++ b/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor @@ -0,0 +1,76 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: kernel sequences byte-arrays namespaces accessors classes math +math.order fry arrays combinators compiler.cfg.registers +compiler.cfg.instructions compiler.cfg.dataflow-analysis ; +IN: compiler.cfg.stacks.uninitialized + +! Uninitialized stack location analysis. + +! Consider the following sequence of instructions: +! ##inc-d 2 +! _gc +! ##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. + + ] [ prepend ] } + } cond + ] 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 ; + +M: ##peek visit-insn + dup loc>> [ n>> ] [ class get ] bi ?nth 0 = + [ uninitialized-peek ] [ drop ] if ; + +M: ##replace visit-insn + loc>> [ n>> ] [ class get ] bi + 2dup length < [ [ 1 ] 2dip set-nth ] [ 2drop ] if ; + +M: insn visit-insn drop ; + +: prepare ( pair -- ) + [ first2 [ [ clone ] [ B{ } ] if* ] bi@ ] [ B{ } B{ } ] if* + [ ds-loc set ] [ rs-loc set ] bi* ; + +: visit-block ( bb -- ) instructions>> [ visit-insn ] each ; + +: finish ( -- pair ) ds-loc get rs-loc get 2array ; + +: (join-sets) ( seq1 seq2 -- seq ) + 2dup [ length ] bi@ max '[ _ 1 pad-tail ] bi@ [ min ] 2map ; + +: (uninitialized-locs) ( seq quot -- seq' ) + [ dup length [ drop 0 = ] pusher [ 2each ] dip ] dip map ; inline + +PRIVATE> + +FORWARD-ANALYSIS: uninitialized + +M: uninitialized-analysis transfer-set ( pair bb analysis -- pair' ) + drop [ prepare ] dip visit-block finish ; + +M: uninitialized-analysis join-sets ( sets analysis -- pair ) + drop sift [ f ] [ [ ] [ [ (join-sets) ] 2map ] map-reduce ] if-empty ; + +: uninitialized-locs ( bb -- locs ) + uninitialized-in dup [ + first2 + [ [ ] (uninitialized-locs) ] + [ [ ] (uninitialized-locs) ] + bi* append + ] when ; \ No newline at end of file diff --git a/basis/compiler/codegen/codegen.factor b/basis/compiler/codegen/codegen.factor index f9a4786eb5..c387c4ed8d 100755 --- a/basis/compiler/codegen/codegen.factor +++ b/basis/compiler/codegen/codegen.factor @@ -221,6 +221,7 @@ M: _gc generate-insn [ temp2>> ] [ gc-roots>> ] [ gc-root-count>> ] + [ uninitialized-locs>> ] } cleave %gc ; M: _loop-entry generate-insn drop %loop-entry ; diff --git a/basis/cpu/architecture/architecture.factor b/basis/cpu/architecture/architecture.factor index deb44db41a..b22e91056f 100644 --- a/basis/cpu/architecture/architecture.factor +++ b/basis/cpu/architecture/architecture.factor @@ -128,7 +128,7 @@ HOOK: %alien-global cpu ( dst symbol library -- ) HOOK: %allot cpu ( dst size class temp -- ) HOOK: %write-barrier cpu ( src card# table -- ) -HOOK: %gc cpu ( temp1 temp2 live-registers live-spill-slots -- ) +HOOK: %gc cpu ( temp1 temp2 live-registers live-spill-slots uninitialized-locs -- ) HOOK: %prologue cpu ( n -- ) HOOK: %epilogue cpu ( n -- ) diff --git a/basis/cpu/x86/x86.factor b/basis/cpu/x86/x86.factor index 5bad8e067c..4fad6d4efc 100644 --- a/basis/cpu/x86/x86.factor +++ b/basis/cpu/x86/x86.factor @@ -466,6 +466,10 @@ M:: word load-gc-root ( gc-root register temp -- ) : load-gc-roots ( gc-roots temp -- ) '[ _ load-gc-root ] assoc-each ; +: wipe-locs ( locs -- ) + ! See explanation in compiler.cfg.stacks.uninitialized + [ 0 ] dip [ %replace ] with each ; + :: call-gc ( gc-root-count -- ) ! Pass pointer to start of GC roots as first parameter param-reg-1 gc-root-base param@ LEA @@ -475,11 +479,12 @@ M:: word load-gc-root ( gc-root register temp -- ) %prepare-alien-invoke "inline_gc" f %alien-invoke ; -M:: x86 %gc ( temp1 temp2 gc-roots gc-root-count -- ) +M:: x86 %gc ( temp1 temp2 gc-roots gc-root-count uninitialized-locs -- ) "end" define-label temp1 temp2 check-nursery "end" get JLE gc-roots temp1 save-gc-roots + uninitialized-locs wipe-locs gc-root-count call-gc gc-roots temp1 load-gc-roots "end" resolve-label ;