generational gc and compiler relocation fixes

cvs
Slava Pestov 2005-05-13 22:27:18 +00:00
parent 41b5a344b8
commit 3b5855a195
17 changed files with 133 additions and 83 deletions

View File

@ -6,6 +6,10 @@
<magnus--> http://www.caddr.com/macho/archives/sbcl-devel/2005-3/4764.html <magnus--> http://www.caddr.com/macho/archives/sbcl-devel/2005-3/4764.html
<magnus--> http://clozure.com/cgi-bin/viewcvs.cgi/ccl/lisp-kernel/lisp-exceptions.c?rev=1.9&content-type=text/vnd.viewcvs-markup <magnus--> http://clozure.com/cgi-bin/viewcvs.cgi/ccl/lisp-kernel/lisp-exceptions.c?rev=1.9&content-type=text/vnd.viewcvs-markup
- simplifier:
- dead loads not optimized out
- kill tag-fixnum/untag-fixnum
- \ foo where foo is parsing is not printed readably
- faster layout - faster layout
- tiled window manager - tiled window manager
- c primitive arrays: or just specialized arrays - c primitive arrays: or just specialized arrays
@ -17,6 +21,8 @@
- sleep word - sleep word
- update docs - update docs
- redo new compiler backend for PowerPC - redo new compiler backend for PowerPC
- type predicates: : foo? type 7 eq? ;
- remove 'not' word, and move t?/f? to kernel
- plugin: supportsBackspace - plugin: supportsBackspace
- if external factor is down, don't add tons of random shit to the - if external factor is down, don't add tons of random shit to the

View File

@ -13,7 +13,7 @@ kernel lists namespaces prettyprint stdio words ;
: compiling ( word -- word parameter ) : compiling ( word -- word parameter )
check-architecture check-architecture
"Compiling " write dup . flush "Compiling " write dup word. terpri flush
dup word-def ; dup word-def ;
GENERIC: (compile) ( word -- ) GENERIC: (compile) ( word -- )
@ -43,7 +43,7 @@ M: compound (compile) ( word -- )
"compile" get [ word compile ] when ; parsing "compile" get [ word compile ] when ; parsing
: cannot-compile ( word error -- ) : cannot-compile ( word error -- )
"Cannot compile " write swap . print-error ; "Cannot compile " write swap word. terpri print-error ;
: try-compile ( word -- ) : try-compile ( word -- )
[ compile ] [ [ cannot-compile ] when* ] catch ; [ compile ] [ [ cannot-compile ] when* ] catch ;
@ -52,7 +52,7 @@ M: compound (compile) ( word -- )
: decompile ( word -- ) : decompile ( word -- )
dup compiled? [ dup compiled? [
"Decompiling " write dup . flush "Decompiling " write dup word. terpri flush
[ word-primitive ] keep set-word-primitive [ word-primitive ] keep set-word-primitive
] [ ] [
drop drop

View File

@ -5,7 +5,7 @@ USING: alien compiler inference kernel kernel-internals lists
math memory namespaces words ; math memory namespaces words ;
\ alien-invoke [ \ alien-invoke [
uncons load-library 2dup rel-dlsym-16/16 dlsym compile-call-far uncons load-library 2dup 1 rel-dlsym dlsym compile-call-far
] "generator" set-word-prop ] "generator" set-word-prop
: stack-size 8 + 16 align ; : stack-size 8 + 16 align ;
@ -16,7 +16,7 @@ math memory namespaces words ;
] "generator" set-word-prop ] "generator" set-word-prop
#unbox [ #unbox [
uncons f 2dup rel-dlsym-16/16 dlsym compile-call-far uncons f 2dup 1 rel-dlsym dlsym compile-call-far
3 1 rot stack@ STW 3 1 rot stack@ STW
] "generator" set-word-prop ] "generator" set-word-prop
@ -25,7 +25,7 @@ math memory namespaces words ;
] "generator" set-word-prop ] "generator" set-word-prop
#box [ #box [
f 2dup rel-dlsym-16/16 dlsym compile-call-far f 2dup 1 rel-dlsym dlsym compile-call-far
] "generator" set-word-prop ] "generator" set-word-prop
#cleanup [ #cleanup [

View File

@ -46,14 +46,14 @@ words ;
: compile-call-label ( label -- ) : compile-call-label ( label -- )
dup primitive? [ dup primitive? [
dup rel-primitive-16/16 word-xt compile-call-far dup 1 rel-primitive word-xt compile-call-far
] [ ] [
0 BL relative-24 0 BL relative-24
] ifte ; ] ifte ;
#call-label [ #call-label [
! Hack: length of instruction sequence that follows ! Hack: length of instruction sequence that follows
rel-address-16/16 compiled-offset 20 + 18 LOAD32 0 1 rel-address compiled-offset 20 + 18 LOAD32
1 1 -16 STWU 1 1 -16 STWU
18 1 20 STW 18 1 20 STW
0 B relative-24 0 B relative-24
@ -66,7 +66,7 @@ words ;
: compile-jump-label ( label -- ) : compile-jump-label ( label -- )
dup primitive? [ dup primitive? [
dup rel-primitive-16/16 word-xt compile-jump-far dup 1 rel-primitive word-xt compile-jump-far
] [ ] [
0 B relative-24 0 B relative-24
] ifte ; ] ifte ;
@ -94,7 +94,7 @@ words ;
18 18 1 SRAWI 18 18 1 SRAWI
! The value 24 is a magic number. It is the length of the ! The value 24 is a magic number. It is the length of the
! instruction sequence that follows to be generated. ! instruction sequence that follows to be generated.
rel-address-16/16 compiled-offset 24 + 19 LOAD32 0 1 rel-address compiled-offset 24 + 19 LOAD32
18 18 19 ADD 18 18 19 ADD
18 18 0 LWZ 18 18 0 LWZ
18 MTLR 18 MTLR

View File

@ -11,34 +11,20 @@ SYMBOL: relocation-table
: relocating compiled-offset cell - rel, ; : relocating compiled-offset cell - rel, ;
: rel-primitive ( word rel/abs -- ) : rel-type, ( rel/abs 16/16 type -- )
#! If flag is true; relative. swap 8 shift bitor swap 16 shift bitor rel, ;
0 1 ? rel, relocating word-primitive rel, ;
: rel-dlsym ( name dll rel/abs -- ) : rel-primitive ( word relative 16/16 -- )
#! If flag is true; relative. 0 rel-type, relocating word-primitive rel, ;
2 3 ? rel, relocating cons intern-literal rel, ;
: rel-address ( rel/abs -- ) : rel-dlsym ( name dll rel/abs 16/16 -- )
1 rel-type, relocating cons intern-literal rel, ;
: rel-address ( rel/abs 16/16 -- )
#! Relocate address just compiled. If flag is true, #! Relocate address just compiled. If flag is true,
#! relative, and there is nothing to do. #! relative, and there is nothing to do.
[ 4 rel, relocating 0 rel, ] unless ; over [ 2drop ] [ 2 rel-type, relocating 0 rel, ] ifte ;
: rel-word ( word rel/abs -- ) : rel-word ( word rel/abs 16/16 -- )
#! If flag is true; relative. #! If flag is true; relative.
over primitive? [ rel-primitive ] [ nip rel-address ] ifte ; over primitive? [ rel-primitive ] [ nip rel-address ] ifte ;
! PowerPC relocations
: rel-primitive-16/16 ( word -- )
#! This is called before a sequence like
#! 19 LOAD32
#! 19 MTCTR
#! BCTR
5 rel, compiled-offset rel, word-primitive rel, ;
: rel-dlsym-16/16 ( name dll -- )
6 rel, compiled-offset rel, cons intern-literal rel, ;
: rel-address-16/16 ( -- )
7 rel, compiled-offset rel, 0 rel, ;

View File

@ -15,7 +15,7 @@ M: vreg v>operand vreg-n { EAX ECX EDX } nth ;
M: %prologue generate-node drop ; M: %prologue generate-node drop ;
: compile-c-call ( symbol dll -- ) : compile-c-call ( symbol dll -- )
2dup dlsym CALL t rel-dlsym ; 2dup dlsym CALL 1 0 rel-dlsym ;
M: %call generate-node ( vop -- ) M: %call generate-node ( vop -- )
vop-label dup postpone-word CALL ; vop-label dup postpone-word CALL ;
@ -58,7 +58,7 @@ M: %dispatch generate-node ( vop -- )
! Multiply by 4 to get a jump table offset ! Multiply by 4 to get a jump table offset
dup 2 SHL dup 2 SHL
! Add to jump table base ! Add to jump table base
dup HEX: ffff ADD just-compiled >r f rel-address dup HEX: ffff ADD just-compiled >r 0 0 rel-address
! Jump to jump table entry ! Jump to jump table entry
unit JMP unit JMP
! Align for better performance ! Align for better performance

View File

@ -7,7 +7,7 @@ memory sequences words ;
: rel-cs ( -- ) : rel-cs ( -- )
#! Add an entry to the relocation table for the 32-bit #! Add an entry to the relocation table for the 32-bit
#! immediate just compiled. #! immediate just compiled.
"cs" f f rel-dlsym ; "cs" f 0 0 rel-dlsym ;
: CS ( -- [ address ] ) "cs" f dlsym unit ; : CS ( -- [ address ] ) "cs" f dlsym unit ;
: CS> ( register -- ) CS MOV rel-cs ; : CS> ( register -- ) CS MOV rel-cs ;
@ -34,7 +34,7 @@ M: %immediate-d generate-node ( vop -- )
vop-literal [ ESI ] swap address MOV ; vop-literal [ ESI ] swap address MOV ;
: load-indirect ( dest literal -- ) : load-indirect ( dest literal -- )
intern-literal unit MOV f rel-address ; intern-literal unit MOV 0 0 rel-address ;
M: %indirect generate-node ( vop -- ) M: %indirect generate-node ( vop -- )
#! indirect load of a literal through a table #! indirect load of a literal through a table

View File

@ -49,7 +49,7 @@ TUPLE: relative word where to ;
: just-compiled compiled-offset 4 - ; : just-compiled compiled-offset 4 - ;
C: relative ( word -- ) C: relative ( word -- )
over t rel-word over 1 0 rel-word
[ set-relative-word ] keep [ set-relative-word ] keep
[ just-compiled swap set-relative-where ] keep [ just-compiled swap set-relative-where ] keep
[ compiled-offset swap set-relative-to ] keep ; [ compiled-offset swap set-relative-to ] keep ;
@ -71,7 +71,7 @@ C: absolute ( word -- )
[ just-compiled swap set-absolute-where ] keep ; [ just-compiled swap set-absolute-where ] keep ;
: absolute ( word -- ) : absolute ( word -- )
dup f rel-word <absolute> deferred-xt ; dup 0 0 rel-word <absolute> deferred-xt ;
: >absolute dup absolute-word compiled-xt swap absolute-where ; : >absolute dup absolute-word compiled-xt swap absolute-where ;

View File

@ -16,7 +16,7 @@ hashtables errors sequences vectors ;
#! Internal allocation function. Do not call it directly, #! Internal allocation function. Do not call it directly,
#! since you can fool the runtime and corrupt memory by #! since you can fool the runtime and corrupt memory by
#! specifying an incorrect size. #! specifying an incorrect size.
<tuple> [ 0 swap set-array-nth ] keep ; <tuple> [ 2 set-slot ] keep ;
: class-tuple 2 slot ; inline : class-tuple 2 slot ; inline

View File

@ -4,6 +4,10 @@ USE: kernel
USE: math USE: math
USE: test USE: test
USE: math-internals USE: math-internals
USE: namespaces
! Four fibonacci implementations, each one slower than the
! previous.
: fixnum-fib ( n -- nth fibonacci number ) : fixnum-fib ( n -- nth fibonacci number )
dup 1 fixnum<= [ dup 1 fixnum<= [
@ -36,3 +40,18 @@ TUPLE: box i ;
] ifte ; compiled ] ifte ; compiled
[ << box f 9227465 >> ] [ << box f 34 >> tuple-fib ] unit-test [ << box f 9227465 >> ] [ << box f 34 >> tuple-fib ] unit-test
SYMBOL: n
: namespace-fib ( n -- n )
[
n set
n get 1 <= [
1
] [
n get 1 - namespace-fib
n get 2 - namespace-fib
+
] ifte
] with-scope ; compiled
[ 9227465 ] [ 34 namespace-fib ] unit-test

View File

@ -87,7 +87,7 @@ SYMBOL: failures
"buffer" , "buffer" ,
] when ] when
cpu "unknown" = "compile" get and [ cpu "unknown" = not "compile" get and [
[ [
"io/buffer" "compiler/optimizer" "io/buffer" "compiler/optimizer"
"compiler/simple" "compiler/simple"
@ -95,7 +95,7 @@ SYMBOL: failures
"compiler/generic" "compiler/bail-out" "compiler/generic" "compiler/bail-out"
"compiler/linearizer" "compiler/intrinsics" "compiler/linearizer" "compiler/intrinsics"
] % ] %
] unless ] when
[ [
"benchmark/empty-loop" "benchmark/fac" "benchmark/empty-loop" "benchmark/fac"

View File

@ -18,6 +18,8 @@ INLINE void collect_card(CARD *ptr, CELL here)
while(card_scan < card_end && card_scan < here) while(card_scan < card_end && card_scan < here)
card_scan = collect_next(card_scan); card_scan = collect_next(card_scan);
cards_scanned++;
} }
INLINE void collect_gen_cards(CELL gen) INLINE void collect_gen_cards(CELL gen)
@ -48,8 +50,9 @@ void unmark_cards(CELL from, CELL to)
void clear_cards(CELL from, CELL to) void clear_cards(CELL from, CELL to)
{ {
CARD *ptr = ADDR_TO_CARD(generations[from].base); /* NOTE: reverse order due to heap layout. */
CARD *last_card = ADDR_TO_CARD(generations[to].limit); CARD *last_card = ADDR_TO_CARD(generations[from].limit);
CARD *ptr = ADDR_TO_CARD(generations[to].base);
for(; ptr < last_card; ptr++) for(; ptr < last_card; ptr++)
clear_card(ptr); clear_card(ptr);
} }

View File

@ -274,10 +274,10 @@ void factorbug(void)
else if(strcmp(cmd,"i") == 0) else if(strcmp(cmd,"i") == 0)
{ {
fprintf(stderr,"Call frame:\n"); fprintf(stderr,"Call frame:\n");
dump_cell(callframe); print_obj(callframe);
fprintf(stderr,"\n"); fprintf(stderr,"\n");
fprintf(stderr,"Executing:\n"); fprintf(stderr,"Executing:\n");
dump_cell(executing); print_obj(executing);
fprintf(stderr,"\n"); fprintf(stderr,"\n");
} }
else if(strcmp(cmd,"e") == 0) else if(strcmp(cmd,"e") == 0)

View File

@ -44,7 +44,7 @@ void init_arena(CELL young_size, CELL aging_size)
for(i = GC_GENERATIONS - 2; i >= 0; i--) for(i = GC_GENERATIONS - 2; i >= 0; i--)
alloter = init_zone(&generations[i],young_size,alloter); alloter = init_zone(&generations[i],young_size,alloter);
clear_cards(TENURED,NURSERY); clear_cards(NURSERY,TENURED);
if(alloter != heap_start + total_size) if(alloter != heap_start + total_size)
fatal_error("Oops",alloter); fatal_error("Oops",alloter);
@ -52,6 +52,8 @@ void init_arena(CELL young_size, CELL aging_size)
allot_profiling = false; allot_profiling = false;
heap_scan = false; heap_scan = false;
gc_time = 0; gc_time = 0;
minor_collections = 0;
cards_scanned = 0;
} }
void collect_roots(void) void collect_roots(void)
@ -78,18 +80,6 @@ void collect_roots(void)
copy_handle(&userenv[i]); copy_handle(&userenv[i]);
} }
/* follow a chain of forwarding pointers */
CELL resolve_forwarding(CELL untagged, CELL tag)
{
CELL header = get(untagged);
/* another forwarding pointer */
if(TAG(header) == GC_COLLECTED)
return resolve_forwarding(UNTAG(header),tag);
/* we've found the destination */
else
return RETAG(untagged,tag);
}
/* Given a pointer to oldspace, copy it to newspace. */ /* Given a pointer to oldspace, copy it to newspace. */
INLINE void *copy_untagged_object(void *pointer, CELL size) INLINE void *copy_untagged_object(void *pointer, CELL size)
{ {
@ -103,12 +93,7 @@ INLINE void *copy_untagged_object(void *pointer, CELL size)
INLINE CELL copy_object_impl(CELL pointer) INLINE CELL copy_object_impl(CELL pointer)
{ {
CELL newpointer; CELL newpointer = (CELL)copy_untagged_object((void*)UNTAG(pointer),
if(pointer < collecting_generation)
critical_error("asked to copy object outside collected generation",pointer);
newpointer = (CELL)copy_untagged_object((void*)UNTAG(pointer),
object_size(pointer)); object_size(pointer));
/* install forwarding pointer */ /* install forwarding pointer */
@ -117,6 +102,23 @@ INLINE CELL copy_object_impl(CELL pointer)
return newpointer; return newpointer;
} }
/* follow a chain of forwarding pointers */
CELL resolve_forwarding(CELL untagged, CELL tag)
{
CELL header = get(untagged);
/* another forwarding pointer */
if(TAG(header) == GC_COLLECTED)
return resolve_forwarding(UNTAG(header),tag);
/* we've found the destination */
else
{
CELL pointer = RETAG(untagged,tag);
if(should_copy(untagged))
pointer = RETAG(copy_object_impl(pointer),tag);
return pointer;
}
}
/* /*
Given a pointer to a tagged pointer to oldspace, copy it to newspace. Given a pointer to a tagged pointer to oldspace, copy it to newspace.
If the object has already been copied, return the forwarding If the object has already been copied, return the forwarding
@ -202,7 +204,8 @@ void reset_generations(CELL from, CELL to)
void begin_gc(CELL gen) void begin_gc(CELL gen)
{ {
collecting_generation = generations[gen].base; collecting_gen = gen;
collecting_gen_start = generations[gen].base;
if(gen == TENURED) if(gen == TENURED)
{ {
@ -234,7 +237,12 @@ void end_gc(CELL gen)
unmark_cards(TENURED,TENURED); unmark_cards(TENURED,TENURED);
/* all generations except tenured space are /* all generations except tenured space are
now empty */ now empty */
reset_generations(TENURED - 1,NURSERY); reset_generations(NURSERY,TENURED - 1);
fprintf(stderr,"*** Major GC (%ld minor, %ld cards)\n",
minor_collections,cards_scanned);
minor_collections = 0;
cards_scanned = 0;
} }
else else
{ {
@ -245,7 +253,9 @@ void end_gc(CELL gen)
unmark_cards(gen + 1,gen + 1); unmark_cards(gen + 1,gen + 1);
/* all generations up to and including the one /* all generations up to and including the one
collected are now empty */ collected are now empty */
reset_generations(gen,NURSERY); reset_generations(NURSERY,gen);
minor_collections++;
} }
} }
@ -308,7 +318,18 @@ are also reachable via the GC roots. */
void maybe_garbage_collection(void) void maybe_garbage_collection(void)
{ {
if(nursery.here > nursery.alarm) if(nursery.here > nursery.alarm)
garbage_collection(NURSERY); {
CELL gen = NURSERY;
while(gen < TENURED)
{
ZONE *z = &generations[gen + 1];
if(z->here < z->alarm)
break;
gen++;
}
garbage_collection(gen);
}
} }
void primitive_gc_time(void) void primitive_gc_time(void)

View File

@ -37,16 +37,20 @@ CELL init_zone(ZONE *z, CELL size, CELL base);
void init_arena(CELL young_size, CELL aging_size); void init_arena(CELL young_size, CELL aging_size);
/* statistics */
s64 gc_time; s64 gc_time;
CELL minor_collections;
CELL cards_scanned;
/* only meaningful during a GC */ /* only meaningful during a GC */
CELL collecting_generation; CELL collecting_gen;
CELL collecting_gen_start;
/* test if the pointer is in generation being collected, or a younger one. /* test if the pointer is in generation being collected, or a younger one.
init_arena() arranges things so that the older generations are first, init_arena() arranges things so that the older generations are first,
so we have to check that the pointer occurs after the beginning of so we have to check that the pointer occurs after the beginning of
the requested generation. */ the requested generation. */
#define COLLECTING_GEN(ptr) (collecting_generation <= ptr) #define COLLECTING_GEN(ptr) (collecting_gen_start <= ptr)
/* #define GC_DEBUG */ /* #define GC_DEBUG */
@ -56,6 +60,14 @@ INLINE void gc_debug(char* msg, CELL x) {
#endif #endif
} }
INLINE bool should_copy(CELL untagged)
{
if(collecting_gen == TENURED)
return !in_zone(newspace,untagged);
else
return(in_zone(&prior,untagged) || COLLECTING_GEN(untagged));
}
CELL copy_object(CELL pointer); CELL copy_object(CELL pointer);
#define COPY_OBJECT(lvalue) if(COLLECTING_GEN(lvalue)) lvalue = copy_object(lvalue) #define COPY_OBJECT(lvalue) if(COLLECTING_GEN(lvalue)) lvalue = copy_object(lvalue)

View File

@ -40,8 +40,6 @@ INLINE CELL relocate_data_next(CELL relocating)
CELL size = CELLS; CELL size = CELLS;
CELL cell = get(relocating); CELL cell = get(relocating);
allot_barrier(relocating);
if(headerp(cell)) if(headerp(cell))
{ {
size = untagged_object_size(relocating); size = untagged_object_size(relocating);
@ -69,6 +67,7 @@ void relocate_data()
if(relocating >= tenured.here) if(relocating >= tenured.here)
break; break;
allot_barrier(relocating);
relocating = relocate_data_next(relocating); relocating = relocate_data_next(relocating);
} }
@ -93,7 +92,7 @@ CELL get_rel_symbol(F_REL* rel)
INLINE CELL compute_code_rel(F_REL *rel, CELL original) INLINE CELL compute_code_rel(F_REL *rel, CELL original)
{ {
switch(rel->type) switch(REL_TYPE(rel))
{ {
case F_PRIMITIVE: case F_PRIMITIVE:
return primitive_to_xt(rel->argument); return primitive_to_xt(rel->argument);
@ -133,7 +132,7 @@ INLINE CELL relocate_code_next(CELL relocating)
CELL original; CELL original;
CELL new_value; CELL new_value;
if(rel->risc16_16) if(REL_16_16(rel))
original = reloc_get_16_16(rel->offset); original = reloc_get_16_16(rel->offset);
else else
original = get(rel->offset); original = get(rel->offset);
@ -143,10 +142,10 @@ INLINE CELL relocate_code_next(CELL relocating)
code_fixup(&rel->offset); code_fixup(&rel->offset);
new_value = compute_code_rel(rel,original); new_value = compute_code_rel(rel,original);
if(rel->relative) if(REL_RELATIVE(rel))
new_value -= (rel->offset + CELLS); new_value -= (rel->offset + CELLS);
if(rel->risc16_16) if(REL_16_16(rel))
reloc_set_16_16(rel->offset,new_value); reloc_set_16_16(rel->offset,new_value);
else else
put(rel->offset,new_value); put(rel->offset,new_value);

View File

@ -21,13 +21,17 @@ typedef enum {
F_CARDS F_CARDS
} F_RELTYPE; } F_RELTYPE;
/* the rel type is built like a cell to avoid endian-specific code in
the compiler */
#define REL_TYPE(r) ((r)->type & 0xff)
/* on PowerPC, some values are stored in the high 16 bits of a pair
of consecutive cells */
#define REL_16_16(r) ((r)->type & 0xff00)
#define REL_RELATIVE(r) ((r)->type & 0xff0000)
/* code relocation consists of a table of entries for each fixup */ /* code relocation consists of a table of entries for each fixup */
typedef struct { typedef struct {
u8 type; CELL type;
u8 relative;
/* on PowerPC, some values are stored in the high 16 bits of a pair
of consecutive cells */
u8 risc16_16;
CELL offset; CELL offset;
CELL argument; CELL argument;
} F_REL; } F_REL;