Skip to content

Commit

Permalink
compiler.*: Remove the scrubbing part of the GC maps
Browse files Browse the repository at this point in the history
Instead of generating GC maps which describe which stack locations that
are uninitialized, we emit ##clear instructions for those locations in
front of ##call-gc instructions. This makes the context root scanning
much simpler because the GC can assume that all stack slots are
initialized. It also removes the compiler.cfg.stacks.vacant pass and
seem to reduce the image size slightly because many fewer GC maps needs
to be emitted.
  • Loading branch information
bjourne committed Sep 11, 2016
1 parent bc8525e commit 349f996
Show file tree
Hide file tree
Showing 20 changed files with 105 additions and 284 deletions.
3 changes: 1 addition & 2 deletions basis/compiler/cfg/finalization/finalization.factor
Expand Up @@ -3,7 +3,7 @@
USING: compiler.cfg.build-stack-frame compiler.cfg.gc-checks
compiler.cfg.linear-scan compiler.cfg.representations
compiler.cfg.save-contexts compiler.cfg.ssa.destruction
compiler.cfg.stacks.clearing compiler.cfg.stacks.vacant compiler.cfg.utilities
compiler.cfg.stacks.clearing compiler.cfg.utilities
compiler.cfg.write-barrier ;
IN: compiler.cfg.finalization

Expand All @@ -13,7 +13,6 @@ IN: compiler.cfg.finalization
insert-gc-checks
eliminate-write-barriers
clear-uninitialized
fill-gc-maps
insert-save-contexts
destruct-ssa
linear-scan
Expand Down
2 changes: 1 addition & 1 deletion basis/compiler/cfg/instructions/instructions-docs.factor
Expand Up @@ -399,7 +399,7 @@ HELP: gc-map
}
"The 'gc-roots' and 'derived-roots' slots are initially vreg integers referencing objects that are live during the gc call and needs to be spilled so that they can be traced. In the " { $link emit-gc-map-insn } " word in " { $vocab-link "compiler.cfg.linear-scan.assignment" } " they are converted to spill slots which the collector is able to trace."
}
{ $see-also emit-gc-info-bitmaps fill-gc-map } ;
{ $see-also emit-gc-info-bitmap fill-gc-map } ;

ARTICLE: "compiler.cfg.instructions" "Basic block instructions"
"The " { $vocab-link "compiler.cfg.instructions" } " vocab contains all instruction classes used for generating CFG:s (Call Flow Graphs)."
Expand Down
2 changes: 1 addition & 1 deletion basis/compiler/cfg/instructions/instructions.factor
Expand Up @@ -851,7 +851,7 @@ UNION: gc-map-insn

M: gc-map-insn clone call-next-method [ clone ] change-gc-map ;

TUPLE: gc-map scrub-d scrub-r gc-roots derived-roots ;
TUPLE: gc-map gc-roots derived-roots ;

: <gc-map> ( -- gc-map ) gc-map new ;

Expand Down
4 changes: 2 additions & 2 deletions basis/compiler/cfg/save-contexts/save-contexts-tests.factor
Expand Up @@ -38,7 +38,7 @@ V{
V{
T{ ##inc f D: 3 }
T{ ##box f 4 3 "from_signed_4" int-rep
T{ gc-map { scrub-d B{ 0 0 0 } } { scrub-r B{ } } { gc-roots { } } }
T{ gc-map { gc-roots { } } }
}
} 0 test-bb

Expand All @@ -49,7 +49,7 @@ V{
T{ ##inc f D: 3 }
T{ ##save-context f 5 6 }
T{ ##box f 4 3 "from_signed_4" int-rep
T{ gc-map { scrub-d B{ 0 0 0 } } { scrub-r B{ } } { gc-roots { } } }
T{ gc-map { gc-roots { } } }
}
}
} [
Expand Down
4 changes: 2 additions & 2 deletions basis/compiler/cfg/ssa/destruction/destruction-tests.factor
Expand Up @@ -51,10 +51,10 @@ IN: compiler.cfg.ssa.destruction.tests
{ stack-size 0 }
{ symbols "g_quark_to_string" }
{ dll DLL" libglib-2.0.so" }
{ gc-map T{ gc-map { scrub-d { } } { scrub-r { } } } }
{ gc-map T{ gc-map } }
{ insn# 14 }
}
T{ ##call-gc { gc-map T{ gc-map { scrub-d { } } { scrub-r { } } } } }
T{ ##call-gc { gc-map T{ gc-map } } }
T{ ##box-alien
{ dst 37 }
{ src 36 }
Expand Down
31 changes: 24 additions & 7 deletions basis/compiler/cfg/stacks/clearing/clearing-docs.factor
Expand Up @@ -3,22 +3,34 @@ help.syntax kernel sequences strings ;
IN: compiler.cfg.stacks.clearing

ARTICLE: "compiler.cfg.stacks.clearing" "Uninitialized stack location clearing"
"A compiler pass that inserts " { $link ##replace-imm } " instructions front of unsafe " { $link ##peek } " instructions in the " { $link cfg } ". Consider the following sequence of instructions."
"A compiler pass that inserts " { $link ##clear } " instructions front of instructions which requires the whole stack to be initialized. Consider the following sequence of instructions:"
{ $code
"##inc D: 2"
"##peek RCX D: 2"
"..."
"##allot"
"##replace ... D: 0"
"##replace ... D: 1"
}
"The ##peek can cause a stack underflow and then there will be two uninitialized locations on the data stack that can't be traced. To counteract that, this pass modifies the instruction sequence so that it becomes:"
"The GC check runs before stack locations 0 and 1 have been initialized, so they need to be cleared as they can contain garbage data which could crash Factor if it tries to trace them. This is achieved by computing uninitialized locations with a dataflow analysis (see " { $vocab-link "compiler.cfg.stacks.padding" } ") and then inserting clears so that the instruction sequence becomes:"
{ $code
"##inc D: 2"
"..."
"##clear D: 0"
"##clear D: 1"
"##allot"
"##replace ... D: 0"
"##replace ... D: 1"
}
"Similar dangerous stack 'holes' needs to be padded in the same way to guard unsafe " { $link ##peek } " instructions. E.g:"
{ $code
"##inc D: 2"
"##replace-imm 17 D: 0"
"##replace-imm 17 D: 1"
"##peek RCX D: 2"
} ;
}
"Here the ##peek can cause a stack underflow and then there will be two uninitialized locations on the captured data stack that can't be traced. As in the previous example, ##clears are inserted on locations D: 0 and D: 1." ;

HELP: dangerous-insn?
{ $values { "state" "a stack state" } { "insn" insn } { "?" boolean } }
{ $description "Checks if the instruction is dangerous (can cause a stack underflow). " }
{ $description "Checks if the instruction is dangerous, meaning that the holes in the stack must be filled before it is executed." }
{ $examples
{ $example
"USING: compiler.cfg.instructions compiler.cfg.registers compiler.cfg.stacks.clearing prettyprint ;"
Expand All @@ -30,6 +42,11 @@ HELP: dangerous-insn?
"{ { 0 { } } { 2 { } } } T{ ##peek { loc R: 0 } } dangerous-insn? ."
"f"
}
{ $example
"USING: compiler.cfg.instructions compiler.cfg.registers compiler.cfg.stacks.clearing prettyprint ;"
"{ { 0 { } } { 3 { } } } T{ ##call-gc } dangerous-insn?"
"t"
}
} ;


Expand Down
3 changes: 2 additions & 1 deletion basis/compiler/cfg/stacks/clearing/clearing-tests.factor
Expand Up @@ -18,11 +18,12 @@ IN: compiler.cfg.stacks.clearing.tests

! dangerous-insn?
{
t f t
t f t t
} [
{ { 0 { } } { 0 { } } } T{ ##peek { loc D: 0 } } dangerous-insn?
{ { 1 { } } { 0 { } } } T{ ##peek { loc D: 0 } } dangerous-insn?
{ { 2 { 0 1 } } { 0 { } } } T{ ##peek { loc D: 2 } } dangerous-insn?
{ { 0 { } } { 3 { } } } T{ ##call-gc } dangerous-insn?
] unit-test

! state>clears
Expand Down
3 changes: 2 additions & 1 deletion basis/compiler/cfg/stacks/clearing/clearing.factor
Expand Up @@ -8,7 +8,8 @@ IN: compiler.cfg.stacks.clearing
[ f ##clear boa ] map ;

: dangerous-insn? ( state insn -- ? )
{ [ nip ##peek? ] [ underflowable-peek? ] } 2&& ;
[ { [ nip ##peek? ] [ underflowable-peek? ] } 2&& ]
[ gc-map-insn? ] bi or ;

: clearing-insns ( assoc insn -- insns' )
[ insn#>> of ] keep 2dup dangerous-insn? [
Expand Down
4 changes: 2 additions & 2 deletions basis/compiler/cfg/stacks/padding/padding-tests.factor
Expand Up @@ -237,7 +237,7 @@ IN: compiler.cfg.stacks.padding.tests
10 V{
T{ ##inc f D: -3 }
T{ ##peek { dst 0 } { loc D: 0 } }
T{ ##alien-invoke { gc-map T{ gc-map { scrub-d { } } } } }
T{ ##alien-invoke { gc-map T{ gc-map } } }
}
}
} [ over insns>block ] assoc-map dup
Expand Down Expand Up @@ -660,7 +660,7 @@ IN: compiler.cfg.stacks.padding.tests
[
V{
T{ ##inc f D: 1 }
T{ ##alien-invoke { gc-map T{ gc-map { scrub-d { } } } } }
T{ ##alien-invoke { gc-map T{ gc-map } } }
T{ ##peek { loc D: 0 } }
} following-stack-state
] [ vacant-peek? ] must-fail-with
Expand Down
38 changes: 0 additions & 38 deletions basis/compiler/cfg/stacks/vacant/vacant-docs.factor

This file was deleted.

28 changes: 0 additions & 28 deletions basis/compiler/cfg/stacks/vacant/vacant-tests.factor

This file was deleted.

20 changes: 0 additions & 20 deletions basis/compiler/cfg/stacks/vacant/vacant.factor

This file was deleted.

41 changes: 13 additions & 28 deletions basis/compiler/codegen/gc-maps/gc-maps-docs.factor
Expand Up @@ -2,28 +2,18 @@ USING: bit-arrays byte-arrays compiler.cfg compiler.cfg.instructions
compiler.cfg.stack-frame help.markup help.syntax kernel math sequences ;
IN: compiler.codegen.gc-maps

HELP: emit-gc-info-bitmaps
HELP: emit-gc-info-bitmap
{ $values
{ "gc-maps" sequence }
{ "counts" "counts of the three different types of gc checks" }
{ "spill-count" "maximum number of spill slots" }
}
{ $description "Emits the scrub location data in the 'gc-maps' to the make sequence being created. The result is a concatenation of all datastack scrub locations, retainstack scrub locations and gc root locations converted into a byte-array. Given that byte-array and knowledge of the number of scrub locations, the original gc-map can be reconstructed." } ;
{ $description "Emits a bitmap of live locations of spill slots in the 'gc-maps' to the current make sequence." } ;

HELP: emit-scrub
HELP: emit-gc-roots
{ $values
{ "seqs" "a sequence of sequences of 0/1" }
{ "n" "length of the longest sequence" }
}
{ $description "Emits a space-efficient " { $link bit-array } " to the make sequence being created. The outputted array will be of length n times the number of sequences given. Each group of n elements in the array contains true values if the stack location should be scrubbed, and false if it shouldn't." }
{ $examples
{ $example
"USING: bit-arrays byte-arrays compiler.codegen.gc-maps make prettyprint ;"
"[ { B{ 0 } B{ 0 } B{ 1 1 1 0 } } emit-scrub ] ?{ } make . ."
"?{ t f f f t f f f f f f t }\n4"
}
} ;

{ emit-gc-info-bitmaps emit-scrub } related-words
{ "seqs" "a sequence of sequences" }
{ "n" "maximum number of spill slots" }
} { $description "Emits the sequences of spill slots as a sequence of " { $link t } " and " { $link f } " values to the current make sequence." } ;

HELP: emit-uint
{ $values { "n" integer } }
Expand Down Expand Up @@ -59,27 +49,22 @@ HELP: gc-map-here
{ $description "Registers the gc map in the " { $link gc-maps } " dynamic variable at the current compiled offset." } ;

ARTICLE: "compiler.codegen.gc-maps" "GC maps"
"The " { $vocab-link "compiler.codegen.gc-maps" } " handles generating code for keeping track of garbage collection maps. Every code block either ends with:"
"The " { $vocab-link "compiler.codegen.gc-maps" } " vocab serializes a compiled words gc maps into a space-efficient format which is appended to the end of the code block."
$nl
"Every code block generated either ends with:"
{ $list "uint 0" }
"or"
{ $list
{
"bitmap, byte aligned, five subsequences:"
{ $list
"scrubbed data stack locations"
"scrubbed retain stack locations"
"GC root spill slots"
}
"a bitmap representing the indices of the spill slots that contain roots in each gc map"
}
"uint[] base pointers"
"uint[] return addresses"
"uint largest scrubbed data stack location"
"uint largest scrubbed retain stack location"
"uint largest GC root spill slot"
"uint largest derived root spill slot"
"int number of return addresses"
"int number of return addresses/gc maps"
}
"The " { $link gc-map } " tuples of the " { $link cfg } " are serialized to the above format and placed directly after the generated code."
"For example, if there are three gc maps and each contain four roots, then bit 0-3 in the bitmap would indicate liveness of the first gc maps roots, 4-7 of the second and 8-11 of the third."
$nl
"Main entry point:"
{ $subsections emit-gc-maps } ;
Expand Down

0 comments on commit 349f996

Please sign in to comment.