Merge branch 'master' into startup

db4
Doug Coleman 2009-10-20 00:31:45 -04:00
commit 278a6955c5
16 changed files with 295 additions and 205 deletions

View File

@ -33,7 +33,7 @@ ARTICLE: "first-program-logic" "Writing some logic in your first program"
$nl $nl
"In order to be able to call the words defined in the " { $snippet "palindrome" } " vocabulary, you need to issue the following command in the listener:" "In order to be able to call the words defined in the " { $snippet "palindrome" } " vocabulary, you need to issue the following command in the listener:"
{ $code "USE: palindrome" } { $code "USE: palindrome" }
"Now, we will be making some additions to the file. Since the file was loaded by the scaffold tool in the previous step, you need to tell Factor to reload it if it changes. Factor has a handy feature for this; pressing " { $command tool "common" refresh-all } " in the listener window will reload any changed source files. You can also force a single vocabulary to reload:" "Now, we will be making some additions to the file. Since the file was loaded by the scaffold tool in the previous step, you need to tell Factor to reload it if it changes. Factor has a handy feature for this; pressing " { $command tool "common" refresh-all } " in the listener window will reload any changed source files. You can also force a single vocabulary to reload, in case the refresh feature does not pick up changes from disk:"
{ $code "\"palindrome\" reload" } { $code "\"palindrome\" reload" }
"We will now write our first word using " { $link POSTPONE: : } ". This word will test if a string is a palindrome; it will take a string as input, and give back a boolean as output. We will call this word " { $snippet "palindrome?" } ", following a naming convention that words returning booleans have names ending with " { $snippet "?" } "." "We will now write our first word using " { $link POSTPONE: : } ". This word will test if a string is a palindrome; it will take a string as input, and give back a boolean as output. We will call this word " { $snippet "palindrome?" } ", following a naming convention that words returning booleans have names ending with " { $snippet "?" } "."
$nl $nl

View File

@ -1,8 +1,8 @@
USING: accessors ui.gadgets.editors tools.test kernel io USING: accessors ui.gadgets.editors ui.gadgets.editors.private
io.streams.plain definitions namespaces ui.gadgets tools.test kernel io io.streams.plain definitions namespaces
ui.gadgets.grids prettyprint documents ui.gestures ui.gadgets.debug ui.gadgets ui.gadgets.grids prettyprint documents ui.gestures
models documents.elements ui.gadgets.scrollers ui.gadgets.line-support ui.gadgets.debug models documents.elements ui.gadgets.scrollers
sequences ; ui.gadgets.line-support sequences ;
IN: ui.gadgets.editors.tests IN: ui.gadgets.editors.tests
[ "foo bar" ] [ [ "foo bar" ] [
@ -55,6 +55,9 @@ IN: ui.gadgets.editors.tests
[ ] [ <editor> com-join-lines ] unit-test [ ] [ <editor> com-join-lines ] unit-test
[ ] [ <editor> "A" over set-editor-string com-join-lines ] unit-test [ ] [ <editor> "A" over set-editor-string com-join-lines ] unit-test
[ "A B" ] [ <editor> "A\nB" over set-editor-string [ com-join-lines ] [ editor-string ] bi ] unit-test [ "A B" ] [ <editor> "A\nB" over set-editor-string [ com-join-lines ] [ editor-string ] bi ] unit-test
[ "A B\nC\nD" ] [ <editor> "A\nB\nC\nD" over set-editor-string { 0 0 } over set-caret dup mark>caret [ com-join-lines ] [ editor-string ] bi ] unit-test
[ "A\nB C\nD" ] [ <editor> "A\nB\nC\nD" over set-editor-string { 1 0 } over set-caret dup mark>caret [ com-join-lines ] [ editor-string ] bi ] unit-test
[ "A\nB\nC D" ] [ <editor> "A\nB\nC\nD" over set-editor-string { 2 0 } over set-caret dup mark>caret [ com-join-lines ] [ editor-string ] bi ] unit-test
[ 2 ] [ <editor> 20 >>min-rows 20 >>min-cols pref-viewport-dim length ] unit-test [ 2 ] [ <editor> 20 >>min-rows 20 >>min-cols pref-viewport-dim length ] unit-test

View File

@ -17,6 +17,8 @@ caret-color
caret mark caret mark
focused? blink blink-alarm ; focused? blink blink-alarm ;
<PRIVATE
: <loc> ( -- loc ) { 0 0 } <model> ; : <loc> ( -- loc ) { 0 0 } <model> ;
: init-editor-locs ( editor -- editor ) : init-editor-locs ( editor -- editor )
@ -27,6 +29,8 @@ focused? blink blink-alarm ;
COLOR: red >>caret-color COLOR: red >>caret-color
monospace-font >>font ; inline monospace-font >>font ; inline
PRIVATE>
: new-editor ( class -- editor ) : new-editor ( class -- editor )
new-line-gadget new-line-gadget
<document> >>model <document> >>model
@ -36,6 +40,8 @@ focused? blink blink-alarm ;
: <editor> ( -- editor ) : <editor> ( -- editor )
editor new-editor ; editor new-editor ;
<PRIVATE
: activate-editor-model ( editor model -- ) : activate-editor-model ( editor model -- )
[ add-connection ] [ add-connection ]
[ nip activate-model ] [ nip activate-model ]
@ -70,6 +76,8 @@ SYMBOL: blink-interval
bi bi
] [ drop ] if ; ] [ drop ] if ;
PRIVATE>
M: editor graft* M: editor graft*
[ dup caret>> activate-editor-model ] [ dup caret>> activate-editor-model ]
[ dup mark>> activate-editor-model ] bi ; [ dup mark>> activate-editor-model ] bi ;
@ -142,6 +150,8 @@ M: editor ungraft*
] keep scroll>rect ] keep scroll>rect
] [ drop ] if ; ] [ drop ] if ;
<PRIVATE
: draw-caret? ( editor -- ? ) : draw-caret? ( editor -- ? )
{ [ focused?>> ] [ blink>> ] } 1&& ; { [ focused?>> ] [ blink>> ] } 1&& ;
@ -189,6 +199,8 @@ TUPLE: selected-line start end first? last? ;
] 3bi ] 3bi
] if ; ] if ;
PRIVATE>
M: editor draw-line ( line index editor -- ) M: editor draw-line ( line index editor -- )
[ selected-lines get at ] dip over [ selected-lines get at ] dip over
[ draw-selected-line ] [ nip draw-unselected-line ] if ; [ draw-selected-line ] [ nip draw-unselected-line ] if ;
@ -206,6 +218,8 @@ M: editor baseline font>> font-metrics ascent>> ;
M: editor cap-height font>> font-metrics cap-height>> ; M: editor cap-height font>> font-metrics cap-height>> ;
<PRIVATE
: contents-changed ( model editor -- ) : contents-changed ( model editor -- )
[ [ nip caret>> ] [ drop ] 2bi '[ _ validate-loc ] (change-model) ] [ [ nip caret>> ] [ drop ] 2bi '[ _ validate-loc ] (change-model) ]
[ [ nip mark>> ] [ drop ] 2bi '[ _ validate-loc ] (change-model) ] [ [ nip mark>> ] [ drop ] 2bi '[ _ validate-loc ] (change-model) ]
@ -214,6 +228,8 @@ M: editor cap-height font>> font-metrics cap-height>> ;
: caret/mark-changed ( editor -- ) : caret/mark-changed ( editor -- )
[ restart-blinking ] keep scroll>caret ; [ restart-blinking ] keep scroll>caret ;
PRIVATE>
M: editor model-changed M: editor model-changed
{ {
{ [ 2dup model>> eq? ] [ contents-changed ] } { [ 2dup model>> eq? ] [ contents-changed ] }
@ -513,6 +529,8 @@ PRIVATE>
: change-selection ( editor quot -- ) : change-selection ( editor quot -- )
'[ gadget-selection @ ] [ user-input* drop ] bi ; inline '[ gadget-selection @ ] [ user-input* drop ] bi ; inline
<PRIVATE
: join-lines ( string -- string' ) : join-lines ( string -- string' )
"\n" split "\n" split
[ rest-slice [ [ blank? ] trim-head-slice ] change-each ] [ rest-slice [ [ blank? ] trim-head-slice ] change-each ]
@ -520,22 +538,39 @@ PRIVATE>
[ " " join ] [ " " join ]
tri ; tri ;
: this-line-and-next ( document line -- start end )
[ nip 0 swap 2array ]
[ 1 + [ nip ] [ swap doc-line length ] 2bi 2array ]
2bi ;
: last-line? ( document line -- ? ) : last-line? ( document line -- ? )
[ last-line# ] dip = ; [ last-line# ] dip = ;
: prev-line-and-this ( document line -- start end )
swap
[ drop 1 - 0 2array ]
[ [ drop ] [ doc-line length ] 2bi 2array ]
2bi ;
: join-with-prev ( document line -- )
[ prev-line-and-this ] [ drop ] 2bi
[ join-lines ] change-doc-range ;
: this-line-and-next ( document line -- start end )
swap
[ drop 0 2array ]
[ [ 1 + ] dip [ drop ] [ doc-line length ] 2bi 2array ]
2bi ;
: join-with-next ( document line -- )
[ this-line-and-next ] [ drop ] 2bi
[ join-lines ] change-doc-range ;
PRIVATE>
: com-join-lines ( editor -- ) : com-join-lines ( editor -- )
dup gadget-selection? dup gadget-selection?
[ [ join-lines ] change-selection ] [ [ [ join-lines ] change-selection ] [
[ model>> ] [ editor-caret first ] bi [ model>> ] [ editor-caret first ] bi {
2dup last-line? [ 2drop ] [ { [ over last-line# 0 = ] [ 2drop ] }
[ this-line-and-next ] [ drop ] 2bi { [ 2dup last-line? ] [ join-with-prev ] }
[ join-lines ] change-doc-range [ join-with-next ]
] if } cond
] if ; ] if ;
multiline-editor "multiline" f { multiline-editor "multiline" f {
@ -566,6 +601,8 @@ TUPLE: source-editor < multiline-editor ;
! Fields wrap an editor ! Fields wrap an editor
TUPLE: field < border editor min-cols max-cols ; TUPLE: field < border editor min-cols max-cols ;
<PRIVATE
: field-theme ( gadget -- gadget ) : field-theme ( gadget -- gadget )
{ 2 2 } >>size { 2 2 } >>size
{ 1 0 } >>fill { 1 0 } >>fill
@ -576,6 +613,8 @@ TUPLE: field < border editor min-cols max-cols ;
{ 1 0 } >>fill { 1 0 } >>fill
field-theme ; field-theme ;
PRIVATE>
: new-field ( class -- gadget ) : new-field ( class -- gadget )
[ <editor> ] dip new-border [ <editor> ] dip new-border
dup gadget-child >>editor dup gadget-child >>editor

View File

@ -4,7 +4,8 @@ accessors words byte-arrays bit-arrays parser namespaces make
quotations stack-checker vectors growable hashtables sbufs quotations stack-checker vectors growable hashtables sbufs
prettyprint byte-vectors bit-vectors specialized-vectors prettyprint byte-vectors bit-vectors specialized-vectors
definitions generic sets graphs assocs grouping see eval ; definitions generic sets graphs assocs grouping see eval ;
SPECIALIZED-VECTOR: double QUALIFIED-WITH: alien.c-types c
SPECIALIZED-VECTOR: c:double
IN: generic.single.tests IN: generic.single.tests
GENERIC: lo-tag-test ( obj -- obj' ) GENERIC: lo-tag-test ( obj -- obj' )

View File

@ -24,7 +24,6 @@ USING:
quotations quotations
sequences sequences
sequences.deep sequences.deep
syntax
words words
; ;
IN: cpu.8080.emulator IN: cpu.8080.emulator

View File

@ -22,15 +22,13 @@ USING:
ui.gadgets ui.gadgets
ui.gestures ui.gestures
ui.render ui.render
specialized-arrays
; ;
QUALIFIED: threads QUALIFIED: threads
QUALIFIED: system QUALIFIED: system
SPECIALIZED-ARRAY: uchar
IN: space-invaders IN: space-invaders
<<
"uchar" require-c-array
>>
TUPLE: space-invaders < cpu port1 port2i port2o port3o port4lo port4hi port5o bitmap sounds looping? ; TUPLE: space-invaders < cpu port1 port2i port2o port3o port4lo port4hi port5o bitmap sounds looping? ;
CONSTANT: game-width 224 CONSTANT: game-width 224
CONSTANT: game-height 256 CONSTANT: game-height 256

View File

@ -296,7 +296,7 @@ void factor_vm::dump_code_heap()
const char *status; const char *status;
if(scan->type() == FREE_BLOCK_TYPE) if(scan->type() == FREE_BLOCK_TYPE)
status = "free"; status = "free";
else if(scan->marked_p()) else if(code->state->is_marked_p(scan))
{ {
reloc_size += object_size(((code_block *)scan)->relocation); reloc_size += object_size(((code_block *)scan)->relocation);
literal_size += object_size(((code_block *)scan)->literals); literal_size += object_size(((code_block *)scan)->literals);

View File

@ -134,6 +134,8 @@ void factor_vm::collect_full_impl(bool trace_contexts_p)
{ {
full_collector collector(this); full_collector collector(this);
code->state->clear_mark_bits();
collector.trace_roots(); collector.trace_roots();
if(trace_contexts_p) if(trace_contexts_p)
{ {
@ -148,16 +150,6 @@ void factor_vm::collect_full_impl(bool trace_contexts_p)
nursery.here = nursery.start; nursery.here = nursery.start;
} }
/* In both cases, compact code heap before updating code blocks so that
XTs are correct after */
void factor_vm::big_code_heap_update()
{
big_code_heap_updater updater(this);
code->free_unmarked(updater);
code->clear_remembered_set();
}
void factor_vm::collect_growing_heap(cell requested_bytes, void factor_vm::collect_growing_heap(cell requested_bytes,
bool trace_contexts_p, bool trace_contexts_p,
bool compact_code_heap_p) bool compact_code_heap_p)
@ -168,15 +160,18 @@ void factor_vm::collect_growing_heap(cell requested_bytes,
collect_full_impl(trace_contexts_p); collect_full_impl(trace_contexts_p);
delete old; delete old;
if(compact_code_heap_p) compact_code_heap(trace_contexts_p); if(compact_code_heap_p)
{
compact_code_heap(trace_contexts_p);
big_code_heap_updater updater(this);
iterate_code_heap(updater);
}
else
{
big_code_heap_updater updater(this);
code->free_unmarked(updater);
}
big_code_heap_update();
}
void factor_vm::small_code_heap_update()
{
small_code_heap_updater updater(this);
code->free_unmarked(updater);
code->clear_remembered_set(); code->clear_remembered_set();
} }
@ -190,10 +185,16 @@ void factor_vm::collect_full(bool trace_contexts_p, bool compact_code_heap_p)
if(compact_code_heap_p) if(compact_code_heap_p)
{ {
compact_code_heap(trace_contexts_p); compact_code_heap(trace_contexts_p);
big_code_heap_update(); big_code_heap_updater updater(this);
iterate_code_heap(updater);
} }
else else
small_code_heap_update(); {
small_code_heap_updater updater(this);
code->free_unmarked(updater);
}
code->clear_remembered_set();
} }
} }

View File

@ -54,9 +54,6 @@ void factor_vm::gc(gc_op op,
current_gc->op = collect_full_op; current_gc->op = collect_full_op;
break; break;
case collect_full_op: case collect_full_op:
/* Since we start tracing again, any previously
marked code blocks must be re-marked and re-traced */
code->clear_mark_bits();
current_gc->op = collect_growing_heap_op; current_gc->op = collect_growing_heap_op;
break; break;
default: default:

View File

@ -16,9 +16,18 @@ heap::heap(bool secure_gc_, cell size, bool executable_p) : secure_gc(secure_gc_
if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size); if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
seg = new segment(align_page(size),executable_p); seg = new segment(align_page(size),executable_p);
if(!seg) fatal_error("Out of memory in heap allocator",size); if(!seg) fatal_error("Out of memory in heap allocator",size);
state = new mark_bits<heap_block,block_size_increment>(seg->start,size);
clear_free_list(); clear_free_list();
} }
heap::~heap()
{
delete seg;
seg = NULL;
delete state;
state = NULL;
}
void heap::add_to_free_list(free_heap_block *block) void heap::add_to_free_list(free_heap_block *block)
{ {
if(block->size() < free_list_count * block_size_increment) if(block->size() < free_list_count * block_size_increment)
@ -34,52 +43,15 @@ void heap::add_to_free_list(free_heap_block *block)
} }
} }
/* Called after reading the code heap from the image file, and after code GC. /* Called after reading the code heap from the image file, and after code heap
compaction. Makes a free list consisting of one free block, at the very end. */
In the former case, we must add a large free block from compiling.base + size to
compiling.limit. */
void heap::build_free_list(cell size) void heap::build_free_list(cell size)
{ {
heap_block *prev = NULL;
clear_free_list(); clear_free_list();
size = (size + block_size_increment - 1) & ~(block_size_increment - 1);
heap_block *scan = first_block();
free_heap_block *end = (free_heap_block *)(seg->start + size); free_heap_block *end = (free_heap_block *)(seg->start + size);
end->set_type(FREE_BLOCK_TYPE);
/* Add all free blocks to the free list */ end->set_size(seg->end - (cell)end);
while(scan && scan < (heap_block *)end) add_to_free_list(end);
{
if(scan->type() == FREE_BLOCK_TYPE)
add_to_free_list((free_heap_block *)scan);
prev = scan;
scan = next_block(scan);
}
/* If there is room at the end of the heap, add a free block. This
branch is only taken after loading a new image, not after code GC */
if((cell)(end + 1) <= seg->end)
{
end->set_marked_p(false);
end->set_type(FREE_BLOCK_TYPE);
end->set_size(seg->end - (cell)end);
/* add final free block */
add_to_free_list(end);
}
/* This branch is taken if the newly loaded image fits exactly, or
after code GC */
else
{
/* even if there's no room at the end of the heap for a new
free block, we might have to jigger it up by a few bytes in
case prev + prev->size */
if(prev) prev->set_size(seg->end - (cell)prev);
}
} }
void heap::assert_free_block(free_heap_block *block) void heap::assert_free_block(free_heap_block *block)
@ -154,7 +126,6 @@ heap_block *heap::heap_allot(cell size, cell type)
{ {
block = split_free_block(block,size); block = split_free_block(block,size);
block->set_type(type); block->set_type(type);
block->set_marked_p(false);
return block; return block;
} }
else else
@ -170,18 +141,7 @@ void heap::heap_free(heap_block *block)
void heap::mark_block(heap_block *block) void heap::mark_block(heap_block *block)
{ {
block->set_marked_p(true); state->set_marked_p(block,true);
}
void heap::clear_mark_bits()
{
heap_block *scan = first_block();
while(scan)
{
scan->set_marked_p(false);
scan = next_block(scan);
}
} }
/* Compute total sum of sizes of free blocks, and size of largest free block */ /* Compute total sum of sizes of free blocks, and size of largest free block */
@ -210,20 +170,21 @@ void heap::heap_usage(cell *used, cell *total_free, cell *max_free)
} }
} }
/* The size of the heap, not including the last block if it's free */ /* The size of the heap after compaction */
cell heap::heap_size() cell heap::heap_size()
{ {
heap_block *scan = first_block(); heap_block *scan = first_block();
while(next_block(scan) != NULL) while(scan)
scan = next_block(scan); {
if(scan->type() == FREE_BLOCK_TYPE) break;
else scan = next_block(scan);
}
/* this is the last block in the heap, and it is free */ assert(scan->type() == FREE_BLOCK_TYPE);
if(scan->type() == FREE_BLOCK_TYPE) assert((cell)scan + scan->size() == seg->end);
return (cell)scan - seg->start;
/* otherwise the last block is allocated */ return (cell)scan - (cell)first_block();
else
return seg->size;
} }
void heap::compact_heap() void heap::compact_heap()
@ -238,7 +199,7 @@ void heap::compact_heap()
{ {
heap_block *next = next_block(scan); heap_block *next = next_block(scan);
if(scan->type() != FREE_BLOCK_TYPE && scan->marked_p()) if(state->is_marked_p(scan))
{ {
cell size = scan->size(); cell size = scan->size();
memmove(address,scan,size); memmove(address,scan,size);

View File

@ -13,9 +13,11 @@ struct heap {
bool secure_gc; bool secure_gc;
segment *seg; segment *seg;
heap_free_list free; heap_free_list free;
mark_bits<heap_block,block_size_increment> *state;
unordered_map<heap_block *, char *> forwarding; unordered_map<heap_block *, char *> forwarding;
explicit heap(bool secure_gc_, cell size, bool executable_p); explicit heap(bool secure_gc_, cell size, bool executable_p);
~heap();
inline heap_block *next_block(heap_block *block) inline heap_block *next_block(heap_block *block)
{ {
@ -46,7 +48,6 @@ struct heap {
heap_block *heap_allot(cell size, cell type); heap_block *heap_allot(cell size, cell type);
void heap_free(heap_block *block); void heap_free(heap_block *block);
void mark_block(heap_block *block); void mark_block(heap_block *block);
void clear_mark_bits();
void heap_usage(cell *used, cell *total_free, cell *max_free); void heap_usage(cell *used, cell *total_free, cell *max_free);
cell heap_size(); cell heap_size();
void compact_heap(); void compact_heap();
@ -71,11 +72,10 @@ struct heap {
else else
prev = scan; prev = scan;
} }
else if(scan->marked_p()) else if(state->is_marked_p(scan))
{ {
if(prev && prev->type() == FREE_BLOCK_TYPE) if(prev && prev->type() == FREE_BLOCK_TYPE)
add_to_free_list((free_heap_block *)prev); add_to_free_list((free_heap_block *)prev);
scan->set_marked_p(false);
prev = scan; prev = scan;
iter(scan); iter(scan);
} }

View File

@ -67,86 +67,6 @@ void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p)
code->build_free_list(h->code_size); code->build_free_list(h->code_size);
} }
/* Save the current image to disk */
bool factor_vm::save_image(const vm_char *filename)
{
FILE* file;
image_header h;
file = OPEN_WRITE(filename);
if(file == NULL)
{
print_string("Cannot open image file: "); print_native_string(filename); nl();
print_string(strerror(errno)); nl();
return false;
}
h.magic = image_magic;
h.version = image_version;
h.data_relocation_base = data->tenured->start;
h.data_size = data->tenured->here - data->tenured->start;
h.code_relocation_base = code->seg->start;
h.code_size = code->heap_size();
h.true_object = true_object;
h.bignum_zero = bignum_zero;
h.bignum_pos_one = bignum_pos_one;
h.bignum_neg_one = bignum_neg_one;
for(cell i = 0; i < USER_ENV; i++)
h.userenv[i] = (save_env_p(i) ? userenv[i] : false_object);
bool ok = true;
if(fwrite(&h,sizeof(image_header),1,file) != 1) ok = false;
if(fwrite((void*)data->tenured->start,h.data_size,1,file) != 1) ok = false;
if(fwrite(code->first_block(),h.code_size,1,file) != 1) ok = false;
if(fclose(file)) ok = false;
if(!ok)
{
print_string("save-image failed: "); print_string(strerror(errno)); nl();
}
return ok;
}
void factor_vm::primitive_save_image()
{
/* do a full GC to push everything into tenured space */
primitive_compact_gc();
gc_root<byte_array> path(dpop(),this);
path.untag_check(this);
save_image((vm_char *)(path.untagged() + 1));
}
void factor_vm::primitive_save_image_and_exit()
{
/* We unbox this before doing anything else. This is the only point
where we might throw an error, so we have to throw an error here since
later steps destroy the current image. */
gc_root<byte_array> path(dpop(),this);
path.untag_check(this);
/* strip out userenv data which is set on startup anyway */
for(cell i = 0; i < USER_ENV; i++)
{
if(!save_env_p(i)) userenv[i] = false_object;
}
gc(collect_full_op,
0, /* requested size */
false, /* discard objects only reachable from stacks */
true /* compact the code heap */);
/* Save the image */
if(save_image((vm_char *)(path.untagged() + 1)))
exit(0);
else
exit(1);
}
void factor_vm::data_fixup(cell *handle, cell data_relocation_base) void factor_vm::data_fixup(cell *handle, cell data_relocation_base)
{ {
if(immediate_p(*handle)) if(immediate_p(*handle))
@ -353,4 +273,82 @@ void factor_vm::load_image(vm_parameters *p)
userenv[IMAGE_ENV] = allot_alien(false_object,(cell)p->image_path); userenv[IMAGE_ENV] = allot_alien(false_object,(cell)p->image_path);
} }
/* Save the current image to disk */
bool factor_vm::save_image(const vm_char *filename)
{
FILE* file;
image_header h;
file = OPEN_WRITE(filename);
if(file == NULL)
{
print_string("Cannot open image file: "); print_native_string(filename); nl();
print_string(strerror(errno)); nl();
return false;
}
h.magic = image_magic;
h.version = image_version;
h.data_relocation_base = data->tenured->start;
h.data_size = data->tenured->here - data->tenured->start;
h.code_relocation_base = code->seg->start;
h.code_size = code->heap_size();
h.true_object = true_object;
h.bignum_zero = bignum_zero;
h.bignum_pos_one = bignum_pos_one;
h.bignum_neg_one = bignum_neg_one;
for(cell i = 0; i < USER_ENV; i++)
h.userenv[i] = (save_env_p(i) ? userenv[i] : false_object);
bool ok = true;
if(fwrite(&h,sizeof(image_header),1,file) != 1) ok = false;
if(fwrite((void*)data->tenured->start,h.data_size,1,file) != 1) ok = false;
if(fwrite(code->first_block(),h.code_size,1,file) != 1) ok = false;
if(fclose(file)) ok = false;
if(!ok)
{
print_string("save-image failed: "); print_string(strerror(errno)); nl();
}
return ok;
}
void factor_vm::primitive_save_image()
{
/* do a full GC to push everything into tenured space */
primitive_compact_gc();
gc_root<byte_array> path(dpop(),this);
path.untag_check(this);
save_image((vm_char *)(path.untagged() + 1));
}
void factor_vm::primitive_save_image_and_exit()
{
/* We unbox this before doing anything else. This is the only point
where we might throw an error, so we have to throw an error here since
later steps destroy the current image. */
gc_root<byte_array> path(dpop(),this);
path.untag_check(this);
/* strip out userenv data which is set on startup anyway */
for(cell i = 0; i < USER_ENV; i++)
if(!save_env_p(i)) userenv[i] = false_object;
gc(collect_full_op,
0, /* requested size */
false, /* discard objects only reachable from stacks */
true /* compact the code heap */);
/* Save the image */
if(save_image((vm_char *)(path.untagged() + 1)))
exit(0);
else
exit(1);
}
} }

View File

@ -201,15 +201,6 @@ struct heap_block
{ {
cell header; cell header;
bool marked_p() { return header & 1; }
void set_marked_p(bool marked)
{
if(marked)
header |= 1;
else
header &= ~1;
}
cell type() { return (header >> 1) & 0x1f; } cell type() { return (header >> 1) & 0x1f; }
void set_type(cell type) void set_type(cell type)
{ {

103
vm/mark_bits.hpp Normal file
View File

@ -0,0 +1,103 @@
namespace factor
{
const int forwarding_granularity = 128;
template<typename Block, int Granularity> struct mark_bits {
cell start;
cell size;
cell bits_size;
unsigned int *marked;
unsigned int *freed;
cell forwarding_size;
cell *forwarding;
void clear_mark_bits()
{
memset(marked,0,bits_size * sizeof(unsigned int));
}
void clear_free_bits()
{
memset(freed,0,bits_size * sizeof(unsigned int));
}
void clear_forwarding()
{
memset(forwarding,0,forwarding_size * sizeof(cell));
}
explicit mark_bits(cell start_, cell size_) :
start(start_),
size(size_),
bits_size(size / Granularity / 32),
marked(new unsigned int[bits_size]),
freed(new unsigned int[bits_size]),
forwarding_size(size / Granularity / forwarding_granularity),
forwarding(new cell[forwarding_size])
{
clear_mark_bits();
clear_free_bits();
clear_forwarding();
}
~mark_bits()
{
delete[] marked;
marked = NULL;
delete[] freed;
freed = NULL;
delete[] forwarding;
forwarding = NULL;
}
std::pair<cell,cell> bitmap_deref(Block *address)
{
cell word_number = (((cell)address - start) / Granularity);
cell word_index = (word_number >> 5);
cell word_shift = (word_number & 31);
#ifdef FACTOR_DEBUG
assert(word_index < bits_size);
#endif
return std::make_pair(word_index,word_shift);
}
bool bitmap_elt(unsigned int *bits, Block *address)
{
std::pair<cell,cell> pair = bitmap_deref(address);
return (bits[pair.first] & (1 << pair.second)) != 0;
}
void set_bitmap_elt(unsigned int *bits, Block *address, bool flag)
{
std::pair<cell,cell> pair = bitmap_deref(address);
if(flag)
bits[pair.first] |= (1 << pair.second);
else
bits[pair.first] &= ~(1 << pair.second);
}
bool is_marked_p(Block *address)
{
return bitmap_elt(marked,address);
}
void set_marked_p(Block *address, bool marked_p)
{
set_bitmap_elt(marked,address,marked_p);
}
bool is_free_p(Block *address)
{
return bitmap_elt(freed,address);
}
void set_free_p(Block *address, bool free_p)
{
set_bitmap_elt(freed,address,free_p);
}
};
}

View File

@ -78,6 +78,7 @@ namespace factor
#include "words.hpp" #include "words.hpp"
#include "float_bits.hpp" #include "float_bits.hpp"
#include "io.hpp" #include "io.hpp"
#include "mark_bits.hpp"
#include "heap.hpp" #include "heap.hpp"
#include "image.hpp" #include "image.hpp"
#include "alien.hpp" #include "alien.hpp"

View File

@ -253,8 +253,6 @@ struct factor_vm
void collect_nursery(); void collect_nursery();
void collect_aging(); void collect_aging();
void collect_to_tenured(); void collect_to_tenured();
void big_code_heap_update();
void small_code_heap_update();
void collect_full_impl(bool trace_contexts_p); void collect_full_impl(bool trace_contexts_p);
void collect_growing_heap(cell requested_bytes, bool trace_contexts_p, bool compact_code_heap_p); void collect_growing_heap(cell requested_bytes, bool trace_contexts_p, bool compact_code_heap_p);
void collect_full(bool trace_contexts_p, bool compact_code_heap_p); void collect_full(bool trace_contexts_p, bool compact_code_heap_p);