From f65ffc664093e7ecd74fb886293a5159bb26aeb5 Mon Sep 17 00:00:00 2001 From: Jon Harper Date: Wed, 30 Sep 2009 23:08:45 +0900 Subject: [PATCH 01/63] faster implementation of euler023 using a hashtable --- extra/project-euler/023/023.factor | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/extra/project-euler/023/023.factor b/extra/project-euler/023/023.factor index 7c28ebfa6c..79aeccd8b4 100644 --- a/extra/project-euler/023/023.factor +++ b/extra/project-euler/023/023.factor @@ -1,6 +1,6 @@ ! Copyright (c) 2008 Aaron Schaefer. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel math math.ranges project-euler.common sequences sets sorting ; +USING: kernel math math.ranges project-euler.common sequences sets sorting assocs fry ; IN: project-euler.023 ! http://projecteuler.net/index.php?section=problems&id=23 @@ -42,10 +42,9 @@ IN: project-euler.023 [1,b] [ abundant? ] filter ; : possible-sums ( seq -- seq ) - dup { } -rot [ - dupd [ + ] curry map - rot append prune swap rest - ] each drop natural-sort ; + H{ } clone + [ dupd '[ _ [ + _ conjoin ] with each ] each ] + keep keys ; PRIVATE> @@ -53,9 +52,7 @@ PRIVATE> source-023 20161 abundants-upto possible-sums diff sum ; -! TODO: solution is still too slow, although it takes under 1 minute - ! [ euler023 ] time -! 52780 ms run / 3839 ms GC +! 2.15542 seconds SOLUTION: euler023 From bf054fe2b598fc400a4a4cab3a1be3a955a3bc49 Mon Sep 17 00:00:00 2001 From: Jon Harper Date: Thu, 1 Oct 2009 00:05:47 +0900 Subject: [PATCH 02/63] Solution to euler255 (slow and not so pretty) --- extra/project-euler/255/255-tests.factor | 4 + extra/project-euler/255/255.factor | 93 ++++++++++++++++++++++++ extra/project-euler/255/authors.txt | 1 + 3 files changed, 98 insertions(+) create mode 100644 extra/project-euler/255/255-tests.factor create mode 100644 extra/project-euler/255/255.factor create mode 100644 extra/project-euler/255/authors.txt diff --git a/extra/project-euler/255/255-tests.factor b/extra/project-euler/255/255-tests.factor new file mode 100644 index 0000000000..b506144e3d --- /dev/null +++ b/extra/project-euler/255/255-tests.factor @@ -0,0 +1,4 @@ +USING: project-euler.255 tools.test ; +IN: project-euler.255.tests + +[ 4.4474011180 ] [ euler255 ] unit-test diff --git a/extra/project-euler/255/255.factor b/extra/project-euler/255/255.factor new file mode 100644 index 0000000000..57a5c5fec7 --- /dev/null +++ b/extra/project-euler/255/255.factor @@ -0,0 +1,93 @@ +! Copyright (C) 2009 Jon Harper. +! See http://factorcode.org/license.txt for BSD license. +USING: project-euler.common math kernel sequences math.functions math.ranges prettyprint io threads math.parser locals arrays namespaces ; +IN: project-euler.255 + +! http://projecteuler.net/index.php?section=problems&id=255 + +! DESCRIPTION +! ----------- +! We define the rounded-square-root of a positive integer n as the square root of n rounded to the nearest integer. +! +! The following procedure (essentially Heron's method adapted to integer arithmetic) finds the rounded-square-root of n: +! +! Let d be the number of digits of the number n. +! If d is odd, set x_(0) = 2×10^((d-1)⁄2). +! If d is even, set x_(0) = 7×10^((d-2)⁄2). +! Repeat: +! +! until x_(k+1) = x_(k). +! +! As an example, let us find the rounded-square-root of n = 4321. +! n has 4 digits, so x_(0) = 7×10^((4-2)⁄2) = 70. +! +! Since x_(2) = x_(1), we stop here. +! So, after just two iterations, we have found that the rounded-square-root of 4321 is 66 (the actual square root is 65.7343137…). +! +! The number of iterations required when using this method is surprisingly low. +! For example, we can find the rounded-square-root of a 5-digit integer (10,000 ≤ n ≤ 99,999) with an average of 3.2102888889 iterations (the average value was rounded to 10 decimal places). +! +! Using the procedure described above, what is the average number of iterations required to find the rounded-square-root of a 14-digit number (10^(13) ≤ n < 10^(14))? +! Give your answer rounded to 10 decimal places. +! +! Note: The symbols ⌊x⌋ and ⌈x⌉ represent the floor function and ceiling function respectively. +! + + +: euler255 ( -- answer ) + 13 14 (euler255) round-to-10-decimals ; + +SOLUTION: euler255 + diff --git a/extra/project-euler/255/authors.txt b/extra/project-euler/255/authors.txt new file mode 100644 index 0000000000..790786959d --- /dev/null +++ b/extra/project-euler/255/authors.txt @@ -0,0 +1 @@ +Jon Harper \ No newline at end of file From a6a5245edb57fb9ee751c173fb25e4d9b8ba8541 Mon Sep 17 00:00:00 2001 From: Jon Harper Date: Sun, 4 Oct 2009 03:18:04 +0900 Subject: [PATCH 03/63] more library usage and readability improvements --- extra/project-euler/051/051.factor | 52 ++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/extra/project-euler/051/051.factor b/extra/project-euler/051/051.factor index b42a491e3c..ff45e9e58a 100644 --- a/extra/project-euler/051/051.factor +++ b/extra/project-euler/051/051.factor @@ -1,38 +1,60 @@ ! Copyright (C) 2009 Jon Harper. ! See http://factorcode.org/license.txt for BSD license. + +! http://projecteuler.net/index.php?section=problems&id=1 + +! DESCRIPTION +! ----------- + + +! By replacing the first digit of *3, it turns out that +! six of the nine possible values: +! 13, 23, 43, 53, 73, and 83, are all prime. +! By replacing the third and fourth digits of 56**3 with the same digit, +! this 5-digit number is the first example having seven primes among +! the ten generated numbers, yielding the family: +! 56003, 56113, 56333, 56443, 56663, 56773, and 56993. +! Consequently 56003, being the first member of this family, +! is the smallest prime with this property. +! +! Find the smallest prime which, by replacing part of the number +! (not necessarily adjacent digits) with the same digit, +! is part of an eight prime value family. + +! SOLUTION +! -------- + +! for each prime number, count the families it belongs to. When one reaches count of 8, stop, and get the smallest number by replacing * with ones. + USING: assocs kernel math math.combinatorics math.functions math.parser math.primes namespaces project-euler.common -sequences sets strings grouping math.ranges arrays ; +sequences sets strings grouping math.ranges arrays fry math.order ; IN: project-euler.051 - + - [ nip values [ fill-*-with-ones string>number ] map infimum ] + [ nip values [ fill-*-with-ones string>number ] [ min ] map-reduce ] [ drop 1 + (euler051) ] if ; +PRIVATE> + : euler051 ( -- answer ) 2 (euler051) ; + +SOLUTION: euler051 From 4743ffdc187dbc098c102243b463135786588559 Mon Sep 17 00:00:00 2001 From: Keith Lazuka Date: Sun, 4 Oct 2009 07:17:54 -0400 Subject: [PATCH 04/63] help.html: with-nesting-block now maps to an HTML DIV with display: inline-block CSS style This change allowed me to remove the old hack that suppressed newlines in the stream if they occurred immediately after a DIV. --- basis/help/help.factor | 4 ++-- basis/help/markup/markup.factor | 6 ++++-- basis/html/streams/streams.factor | 34 +++++++++---------------------- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/basis/help/help.factor b/basis/help/help.factor index 8f8ad35bf4..ddd6ce23fc 100644 --- a/basis/help/help.factor +++ b/basis/help/help.factor @@ -120,12 +120,12 @@ M: word set-article-parent swap "help-parent" set-word-prop ; title-style get [ [ ($title) ] [ ($navigation) ] bi ] with-nesting - ] with-style nl ; + ] with-style ; : print-topic ( topic -- ) >link last-element off - [ $title ] [ nl article-content print-content nl ] bi ; + [ $title ] [ ($blank-line) article-content print-content ] bi ; SYMBOL: help-hook diff --git a/basis/help/markup/markup.factor b/basis/help/markup/markup.factor index d0cfb675a7..845092fa03 100644 --- a/basis/help/markup/markup.factor +++ b/basis/help/markup/markup.factor @@ -26,6 +26,9 @@ SYMBOL: blank-line last-blank-line? not and [ nl ] when ; +: ($blank-line) ( -- ) + nl nl blank-line last-element set ; + : ($span) ( quot -- ) last-block? [ nl ] when span last-element set @@ -44,7 +47,6 @@ M: f print-element drop ; : with-default-style ( quot -- ) default-span-style get [ - last-element off default-block-style get swap with-nesting ] with-style ; inline @@ -220,7 +222,7 @@ PRIVATE> ] ($subsection) ; : $subsections ( children -- ) - [ $subsection* ] each nl nl blank-line last-element set ; + [ $subsection* ] each ($blank-line) ; : $subsection ( element -- ) first $subsection* ; diff --git a/basis/html/streams/streams.factor b/basis/html/streams/streams.factor index 1b3086f665..c6a2b08c00 100644 --- a/basis/html/streams/streams.factor +++ b/basis/html/streams/streams.factor @@ -10,22 +10,10 @@ GENERIC: url-of ( object -- url ) M: object url-of drop f ; -TUPLE: html-writer data last-div ; +TUPLE: html-writer data ; >last-div ; inline - -: a-div ( stream -- stream ) - t >>last-div ; inline - : new-html-writer ( class -- html-writer ) new V{ } clone >>data ; inline @@ -107,7 +95,7 @@ MACRO: make-css ( pairs -- str ) TUPLE: html-span-stream < html-sub-stream ; M: html-span-stream dispose - end-sub-stream not-a-div format-html-span ; + end-sub-stream format-html-span ; : border-css, ( border -- ) "border: 1px solid #" % hex-color, "; " % ; @@ -124,10 +112,8 @@ CONSTANT: pre-css "white-space: pre; font-family: monospace;" { border-color border-css, } { inset padding-css, } } make-css - ] [ - wrap-margin swap at - [ pre-css append ] unless - ] bi ; + ] [ wrap-margin swap at [ pre-css append ] unless ] bi + "display: inline-block;" append ; : div-tag ( xml style -- xml' ) div-css-style @@ -139,7 +125,7 @@ CONSTANT: pre-css "white-space: pre; font-family: monospace;" TUPLE: html-block-stream < html-sub-stream ; M: html-block-stream dispose ( quot style stream -- ) - end-sub-stream a-div format-html-div ; + end-sub-stream format-html-div ; : border-spacing-css, ( pair -- ) "padding: " % first2 max 2 /i # "px; " % ; @@ -157,16 +143,16 @@ PRIVATE> M: html-writer stream-flush drop ; M: html-writer stream-write1 - not-a-div [ 1string ] emit-html ; + [ 1string ] emit-html ; M: html-writer stream-write - not-a-div [ ] emit-html ; + [ ] emit-html ; M: html-writer stream-format format-html-span ; M: html-writer stream-nl - dup last-div? [ drop ] [ [ [XML
XML] ] emit-html ] if ; + [ [XML
XML] ] emit-html ; M: html-writer make-span-stream html-span-stream new-html-sub-stream ; @@ -178,12 +164,12 @@ M: html-writer make-cell-stream html-sub-stream new-html-sub-stream ; M: html-writer stream-write-table - a-div [ + [ table-style swap [ [ data>> [XML ><-> XML] ] with map [XML <-> XML] ] with map - [XML <->
XML] + [XML <->
XML] ] emit-html ; M: html-writer dispose drop ; From bae2240f623726b0c6fe0449eee5f9d5e3fb4d51 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 5 Oct 2009 22:16:08 -0500 Subject: [PATCH 05/63] vm: refactoring garbage collector --- vm/code_block.cpp | 88 -------- vm/code_heap.cpp | 25 --- vm/data_gc.cpp | 465 +++++++++++++++++++++++++----------------- vm/data_gc.hpp | 5 + vm/data_heap.hpp | 10 +- vm/generic_arrays.hpp | 2 +- vm/strings.cpp | 4 +- vm/vm.hpp | 45 ++-- 8 files changed, 314 insertions(+), 330 deletions(-) diff --git a/vm/code_block.cpp b/vm/code_block.cpp index 54fd455ae4..0ba30d1c0d 100755 --- a/vm/code_block.cpp +++ b/vm/code_block.cpp @@ -298,26 +298,6 @@ void factor_vm::update_literal_references(code_block *compiled) } } -/* Copy all literals referenced from a code block to newspace. Only for -aging and nursery collections */ -void factor_vm::trace_literal_references(code_block *compiled) -{ - if(current_gc->collecting_gen >= compiled->last_scan) - { - if(current_gc->collecting_accumulation_gen_p()) - compiled->last_scan = current_gc->collecting_gen; - else - compiled->last_scan = current_gc->collecting_gen + 1; - - trace_handle(&compiled->literals); - trace_handle(&compiled->relocation); - - /* once we finish tracing, re-visit this code block and update - literals */ - current_gc->dirty_code_blocks.insert(compiled); - } -} - /* Compute an address to store at a relocation */ void factor_vm::relocate_code_block_step(relocation_entry rel, cell index, code_block *compiled) { @@ -377,74 +357,6 @@ void factor_vm::check_code_address(cell address) #endif } -/* Update references to words. This is done after a new code block -is added to the heap. */ - -/* Mark all literals referenced from a word XT. Only for tenured -collections */ -void factor_vm::mark_code_block(code_block *compiled) -{ - check_code_address((cell)compiled); - - code->mark_block(compiled); - - trace_handle(&compiled->literals); - trace_handle(&compiled->relocation); -} - -struct stack_frame_marker { - factor_vm *myvm; - - explicit stack_frame_marker(factor_vm *myvm_) : myvm(myvm_) {} - void operator()(stack_frame *frame) - { - myvm->mark_code_block(myvm->frame_code(frame)); - } -}; - -/* Mark code blocks executing in currently active stack frames. */ -void factor_vm::mark_active_blocks(context *stacks) -{ - if(current_gc->collecting_tenured_p()) - { - cell top = (cell)stacks->callstack_top; - cell bottom = (cell)stacks->callstack_bottom; - - stack_frame_marker marker(this); - iterate_callstack(top,bottom,marker); - } -} - -void factor_vm::mark_object_code_block(object *object) -{ - switch(object->h.hi_tag()) - { - case WORD_TYPE: - { - word *w = (word *)object; - if(w->code) - mark_code_block(w->code); - if(w->profiling) - mark_code_block(w->profiling); - break; - } - case QUOTATION_TYPE: - { - quotation *q = (quotation *)object; - if(q->code) - mark_code_block(q->code); - break; - } - case CALLSTACK_TYPE: - { - callstack *stack = (callstack *)object; - stack_frame_marker marker(this); - iterate_callstack_object(stack,marker); - break; - } - } -} - struct code_block_relocator { factor_vm *myvm; diff --git a/vm/code_heap.cpp b/vm/code_heap.cpp index b45b2ac49f..e44cbeba17 100755 --- a/vm/code_heap.cpp +++ b/vm/code_heap.cpp @@ -28,31 +28,6 @@ void factor_vm::jit_compile_word(cell word_, cell def_, bool relocate) if(word->pic_tail_def != F) jit_compile(word->pic_tail_def,relocate); } -struct literal_reference_tracer { - factor_vm *myvm; - - explicit literal_reference_tracer(factor_vm *myvm_) : myvm(myvm_) {} - void operator()(code_block *compiled) - { - myvm->trace_literal_references(compiled); - } -}; - -/* Copy literals referenced from all code blocks to newspace. Only for -aging and nursery collections */ -void factor_vm::trace_code_heap_roots() -{ - code_heap_scans++; - - literal_reference_tracer tracer(this); - iterate_code_heap(tracer); - - if(current_gc->collecting_accumulation_gen_p()) - last_code_heap_scan = current_gc->collecting_gen; - else - last_code_heap_scan = current_gc->collecting_gen + 1; -} - /* Update pointers to words referenced from all code blocks. Only after defining a new word. */ void factor_vm::update_code_heap_words() diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 60195f89d5..dad6b9c9eb 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -40,48 +40,31 @@ object *factor_vm::copy_object_impl(object *untagged) return newpointer; } -bool factor_vm::should_copy_p(object *untagged) -{ - if(in_zone(current_gc->newspace,untagged)) - return false; - if(current_gc->collecting_tenured_p()) - return true; - else if(data->have_aging_p() && current_gc->collecting_gen == data->aging()) - return !in_zone(&data->generations[data->tenured()],untagged); - else if(current_gc->collecting_nursery_p()) - return in_zone(&nursery,untagged); - else - { - critical_error("Bug in should_copy_p",(cell)untagged); - return false; - } -} - /* Follow a chain of forwarding pointers */ -object *factor_vm::resolve_forwarding(object *untagged) +template object *factor_vm::resolve_forwarding(object *untagged, Strategy &strategy) { check_data_pointer(untagged); /* is there another forwarding pointer? */ if(untagged->h.forwarding_pointer_p()) - return resolve_forwarding(untagged->h.forwarding_pointer()); + return resolve_forwarding(untagged->h.forwarding_pointer(),strategy); /* we've found the destination */ else { untagged->h.check_header(); - if(should_copy_p(untagged)) + if(strategy.should_copy_p(untagged)) return copy_object_impl(untagged); else return untagged; } } -template Type *factor_vm::copy_untagged_object(Type *untagged) +template Type *factor_vm::copy_untagged_object(Type *untagged, Strategy &strategy) { check_data_pointer(untagged); if(untagged->h.forwarding_pointer_p()) - untagged = (Type *)resolve_forwarding(untagged->h.forwarding_pointer()); + untagged = (Type *)resolve_forwarding(untagged->h.forwarding_pointer(),strategy); else { untagged->h.check_header(); @@ -91,12 +74,12 @@ template Type *factor_vm::copy_untagged_object(Type *untagged) return untagged; } -cell factor_vm::copy_object(cell pointer) +template cell factor_vm::copy_object(cell pointer, Strategy &strategy) { - return RETAG(copy_untagged_object(untag(pointer)),TAG(pointer)); + return RETAG(copy_untagged_object(untag(pointer),strategy),TAG(pointer)); } -void factor_vm::trace_handle(cell *handle) +template void factor_vm::trace_handle(cell *handle, Strategy &strategy) { cell pointer = *handle; @@ -104,13 +87,12 @@ void factor_vm::trace_handle(cell *handle) { object *obj = untag(pointer); check_data_pointer(obj); - if(should_copy_p(obj)) - *handle = copy_object(pointer); + if(strategy.should_copy_p(obj)) + *handle = copy_object(pointer,strategy); } } -/* Scan all the objects in the card */ -void factor_vm::trace_card(card *ptr, cell gen, cell here) +template void factor_vm::trace_card(card *ptr, cell gen, cell here, Strategy &strategy) { cell card_scan = card_to_addr(ptr) + card_offset(ptr); cell card_end = card_to_addr(ptr + 1); @@ -118,12 +100,12 @@ void factor_vm::trace_card(card *ptr, cell gen, cell here) if(here < card_end) card_end = here; - copy_reachable_objects(card_scan,&card_end); + strategy.copy_reachable_objects(card_scan,&card_end); cards_scanned++; } -void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmask) +template void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy) { card *first_card = deck_to_card(deck); card *last_card = deck_to_card(deck + 1); @@ -144,7 +126,7 @@ void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmas { if(ptr[card] & mask) { - trace_card(&ptr[card],gen,here); + trace_card(&ptr[card],gen,here,strategy); ptr[card] &= ~unmask; } } @@ -155,7 +137,7 @@ void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmas } /* Copy all newspace objects referenced from marked cards to the destination */ -void factor_vm::trace_generation_cards(cell gen) +template void factor_vm::trace_generation_cards(cell gen, Strategy &strategy) { card_deck *first_deck = addr_to_deck(data->generations[gen].start); card_deck *last_deck = addr_to_deck(data->generations[gen].end); @@ -214,7 +196,7 @@ void factor_vm::trace_generation_cards(cell gen) { if(*ptr & mask) { - trace_card_deck(ptr,gen,mask,unmask); + trace_card_deck(ptr,gen,mask,unmask,strategy); *ptr &= ~unmask; } } @@ -222,36 +204,36 @@ void factor_vm::trace_generation_cards(cell gen) /* Scan cards in all generations older than the one being collected, copying old->new references */ -void factor_vm::trace_cards() +template void factor_vm::trace_cards(Strategy &strategy) { u64 start = current_micros(); cell i; for(i = current_gc->collecting_gen + 1; i < data->gen_count; i++) - trace_generation_cards(i); + trace_generation_cards(i,strategy); card_scan_time += (current_micros() - start); } /* Copy all tagged pointers in a range of memory */ -void factor_vm::trace_stack_elements(segment *region, cell top) +template void factor_vm::trace_stack_elements(segment *region, cell top, Strategy &strategy) { cell ptr = region->start; for(; ptr <= top; ptr += sizeof(cell)) - trace_handle((cell*)ptr); + trace_handle((cell*)ptr,strategy); } -void factor_vm::trace_registered_locals() +template void factor_vm::trace_registered_locals(Strategy &strategy) { std::vector::const_iterator iter = gc_locals.begin(); std::vector::const_iterator end = gc_locals.end(); for(; iter < end; iter++) - trace_handle((cell *)(*iter)); + trace_handle((cell *)(*iter),strategy); } -void factor_vm::trace_registered_bignums() +template void factor_vm::trace_registered_bignums(Strategy &strategy) { std::vector::const_iterator iter = gc_bignums.begin(); std::vector::const_iterator end = gc_bignums.end(); @@ -264,8 +246,8 @@ void factor_vm::trace_registered_bignums() if(pointer) { check_data_pointer(pointer); - if(should_copy_p(pointer)) - *handle = copy_untagged_object(pointer); + if(strategy.should_copy_p(pointer)) + *handle = copy_untagged_object(pointer,strategy); #ifdef FACTOR_DEBUG assert((*handle)->h.hi_tag() == BIGNUM_TYPE); #endif @@ -275,41 +257,156 @@ void factor_vm::trace_registered_bignums() /* Copy roots over at the start of GC, namely various constants, stacks, the user environment and extra roots registered by local_roots.hpp */ -void factor_vm::trace_roots() +template void factor_vm::trace_roots(Strategy &strategy) { - trace_handle(&T); - trace_handle(&bignum_zero); - trace_handle(&bignum_pos_one); - trace_handle(&bignum_neg_one); + trace_handle(&T,strategy); + trace_handle(&bignum_zero,strategy); + trace_handle(&bignum_pos_one,strategy); + trace_handle(&bignum_neg_one,strategy); - trace_registered_locals(); - trace_registered_bignums(); + trace_registered_locals(strategy); + trace_registered_bignums(strategy); int i; for(i = 0; i < USER_ENV; i++) - trace_handle(&userenv[i]); + trace_handle(&userenv[i],strategy); } -void factor_vm::trace_contexts() +template struct stack_frame_marker { + factor_vm *myvm; + Strategy &strategy; + + explicit stack_frame_marker(factor_vm *myvm_, Strategy &strategy_) : + myvm(myvm_), strategy(strategy_) {} + void operator()(stack_frame *frame) + { + myvm->mark_code_block(myvm->frame_code(frame),strategy); + } +}; + +/* Mark code blocks executing in currently active stack frames. */ +template void factor_vm::mark_active_blocks(context *stacks, Strategy &strategy) +{ + if(current_gc->collecting_tenured_p()) + { + cell top = (cell)stacks->callstack_top; + cell bottom = (cell)stacks->callstack_bottom; + + stack_frame_marker marker(this,strategy); + iterate_callstack(top,bottom,marker); + } +} + +template void factor_vm::mark_object_code_block(object *object, Strategy &strategy) +{ + switch(object->h.hi_tag()) + { + case WORD_TYPE: + { + word *w = (word *)object; + if(w->code) + mark_code_block(w->code,strategy); + if(w->profiling) + mark_code_block(w->profiling,strategy); + break; + } + case QUOTATION_TYPE: + { + quotation *q = (quotation *)object; + if(q->code) + mark_code_block(q->code,strategy); + break; + } + case CALLSTACK_TYPE: + { + callstack *stack = (callstack *)object; + stack_frame_marker marker(this,strategy); + iterate_callstack_object(stack,marker); + break; + } + } +} + +template void factor_vm::trace_contexts(Strategy &strategy) { save_stacks(); context *stacks = stack_chain; while(stacks) { - trace_stack_elements(stacks->datastack_region,stacks->datastack); - trace_stack_elements(stacks->retainstack_region,stacks->retainstack); + trace_stack_elements(stacks->datastack_region,stacks->datastack,strategy); + trace_stack_elements(stacks->retainstack_region,stacks->retainstack,strategy); - trace_handle(&stacks->catchstack_save); - trace_handle(&stacks->current_callback_save); + trace_handle(&stacks->catchstack_save,strategy); + trace_handle(&stacks->current_callback_save,strategy); - mark_active_blocks(stacks); + mark_active_blocks(stacks,strategy); stacks = stacks->next; } } -cell factor_vm::copy_next_from_nursery(cell scan) +/* Copy all literals referenced from a code block to newspace. Only for +aging and nursery collections */ +template void factor_vm::trace_literal_references(code_block *compiled, Strategy &strategy) +{ + if(current_gc->collecting_gen >= compiled->last_scan) + { + if(current_gc->collecting_accumulation_gen_p()) + compiled->last_scan = current_gc->collecting_gen; + else + compiled->last_scan = current_gc->collecting_gen + 1; + + trace_handle(&compiled->literals,strategy); + trace_handle(&compiled->relocation,strategy); + + /* once we finish tracing, re-visit this code block and update + literals */ + current_gc->dirty_code_blocks.insert(compiled); + } +} + +template struct literal_reference_tracer { + factor_vm *myvm; + Strategy strategy; + + explicit literal_reference_tracer(factor_vm *myvm_, Strategy &strategy_) : + myvm(myvm_), strategy(strategy_) {} + + void operator()(code_block *compiled) + { + myvm->trace_literal_references(compiled,strategy); + } +}; + +/* Copy literals referenced from all code blocks to newspace. Only for +aging and nursery collections */ +template void factor_vm::trace_code_heap_roots(Strategy &strategy) +{ + literal_reference_tracer tracer(this,strategy); + iterate_code_heap(tracer); + + if(current_gc->collecting_accumulation_gen_p()) + last_code_heap_scan = current_gc->collecting_gen; + else + last_code_heap_scan = current_gc->collecting_gen + 1; + + code_heap_scans++; +} + +/* Mark all literals referenced from a word XT. Only for tenured +collections */ +template void factor_vm::mark_code_block(code_block *compiled, Strategy &strategy) +{ + check_code_address((cell)compiled); + + code->mark_block(compiled); + + trace_handle(&compiled->literals,strategy); + trace_handle(&compiled->relocation,strategy); +} + +template cell factor_vm::copy_next(cell scan, Strategy &strategy) { cell *obj = (cell *)scan; cell *end = (cell *)(scan + binary_payload_start((object *)scan)); @@ -318,113 +415,20 @@ cell factor_vm::copy_next_from_nursery(cell scan) { obj++; - cell nursery_start = nursery.start; - cell nursery_end = nursery.end; - for(; obj < end; obj++) - { - cell pointer = *obj; - - if(!immediate_p(pointer)) - { - check_data_pointer((object *)pointer); - if(pointer >= nursery_start && pointer < nursery_end) - *obj = copy_object(pointer); - } - } + trace_handle(obj,strategy); } return scan + untagged_object_size((object *)scan); } -cell factor_vm::copy_next_from_aging(cell scan) -{ - cell *obj = (cell *)scan; - cell *end = (cell *)(scan + binary_payload_start((object *)scan)); - - if(obj != end) - { - obj++; - - cell tenured_start = data->generations[data->tenured()].start; - cell tenured_end = data->generations[data->tenured()].end; - - cell newspace_start = current_gc->newspace->start; - cell newspace_end = current_gc->newspace->end; - - for(; obj < end; obj++) - { - cell pointer = *obj; - - if(!immediate_p(pointer)) - { - check_data_pointer((object *)pointer); - if(!(pointer >= newspace_start && pointer < newspace_end) - && !(pointer >= tenured_start && pointer < tenured_end)) - *obj = copy_object(pointer); - } - } - } - - return scan + untagged_object_size((object *)scan); -} - -cell factor_vm::copy_next_from_tenured(cell scan) -{ - cell *obj = (cell *)scan; - cell *end = (cell *)(scan + binary_payload_start((object *)scan)); - - if(obj != end) - { - obj++; - - cell newspace_start = current_gc->newspace->start; - cell newspace_end = current_gc->newspace->end; - - for(; obj < end; obj++) - { - cell pointer = *obj; - - if(!immediate_p(pointer)) - { - check_data_pointer((object *)pointer); - if(!(pointer >= newspace_start && pointer < newspace_end)) - *obj = copy_object(pointer); - } - } - } - - mark_object_code_block((object *)scan); - - return scan + untagged_object_size((object *)scan); -} - -void factor_vm::copy_reachable_objects(cell scan, cell *end) -{ - if(current_gc->collecting_nursery_p()) - { - while(scan < *end) - scan = copy_next_from_nursery(scan); - } - else if(data->have_aging_p() && current_gc->collecting_gen == data->aging()) - { - while(scan < *end) - scan = copy_next_from_aging(scan); - } - else if(current_gc->collecting_tenured_p()) - { - while(scan < *end) - scan = copy_next_from_tenured(scan); - } -} - -void factor_vm::update_code_heap_roots() +template void factor_vm::update_code_heap_roots(Strategy &strategy) { if(current_gc->collecting_gen >= last_code_heap_scan) { code_heap_scans++; - trace_code_heap_roots(); + trace_code_heap_roots(strategy); if(current_gc->collecting_accumulation_gen_p()) last_code_heap_scan = current_gc->collecting_gen; @@ -498,6 +502,120 @@ void factor_vm::begin_gc(cell requested_bytes) } } +struct nursery_collector +{ + factor_vm *myvm; + + explicit nursery_collector(factor_vm *myvm_) : myvm(myvm_) {} + + bool should_copy_p(object *untagged) + { + if(myvm->current_gc->newspace->contains_p(untagged)) + return false; + else + return myvm->nursery.contains_p(untagged); + } + + void copy_reachable_objects(cell scan, cell *end) + { + while(scan < myvm->current_gc->newspace->here) + scan = myvm->copy_next(scan,*this); + } +}; + +void factor_vm::collect_nursery() +{ + nursery_collector collector(this); + + cell scan = current_gc->newspace->here; + + trace_roots(collector); + trace_contexts(collector); + trace_cards(collector); + + if(current_gc->collecting_gen >= last_code_heap_scan) + update_code_heap_roots(collector); + + collector.copy_reachable_objects(scan,¤t_gc->newspace->here); + + update_dirty_code_blocks(); +} + +struct aging_collector +{ + factor_vm *myvm; + + explicit aging_collector(factor_vm *myvm_) : myvm(myvm_) {} + + bool should_copy_p(object *untagged) + { + if(myvm->current_gc->newspace->contains_p(untagged)) + return false; + else + return !myvm->data->generations[myvm->data->tenured()].contains_p(untagged); + } + + void copy_reachable_objects(cell scan, cell *end) + { + while(scan < myvm->current_gc->newspace->here) + scan = myvm->copy_next(scan,*this); + } +}; + +void factor_vm::collect_aging() +{ + aging_collector collector(this); + + cell scan = current_gc->newspace->here; + + trace_roots(collector); + trace_contexts(collector); + trace_cards(collector); + + if(current_gc->collecting_gen >= last_code_heap_scan) + update_code_heap_roots(collector); + + collector.copy_reachable_objects(scan,¤t_gc->newspace->here); + + update_dirty_code_blocks(); +} + +struct tenured_collector +{ + factor_vm *myvm; + + explicit tenured_collector(factor_vm *myvm_) : myvm(myvm_) {} + + bool should_copy_p(object *untagged) + { + return !myvm->current_gc->newspace->contains_p(untagged); + } + + void copy_reachable_objects(cell scan, cell *end) + { + while(scan < myvm->current_gc->newspace->here) + { + myvm->mark_object_code_block(myvm->untag(scan),*this); + scan = myvm->copy_next(scan,*this); + } + } +}; + +void factor_vm::collect_tenured(bool trace_contexts_) +{ + tenured_collector collector(this); + + cell scan = current_gc->newspace->here; + + trace_roots(collector); + if(trace_contexts_) + trace_contexts(collector); + + collector.copy_reachable_objects(scan,¤t_gc->newspace->here); + + free_unmarked_code_blocks(); +} + void factor_vm::end_gc() { gc_stats *s = &stats[current_gc->collecting_gen]; @@ -572,40 +690,13 @@ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_ begin_gc(requested_bytes); - /* Initialize chase pointer */ - cell scan = current_gc->newspace->here; + if(current_gc->collecting_nursery_p()) + collect_nursery(); + else if(current_gc->collecting_aging_p()) + collect_aging(); + else if(current_gc->collecting_tenured_p()) + collect_tenured(trace_contexts_); - /* Trace objects referenced from global environment */ - trace_roots(); - - /* Trace objects referenced from stacks, unless we're doing - save-image-and-exit in which case stack objects are irrelevant */ - if(trace_contexts_) trace_contexts(); - - /* Trace objects referenced from older generations */ - trace_cards(); - - /* On minor GC, trace code heap roots if it has pointers - to this generation or younger. Otherwise, tracing data heap objects - will mark all reachable code blocks, and we free the unmarked ones - after. */ - if(!current_gc->collecting_tenured_p() && current_gc->collecting_gen >= last_code_heap_scan) - { - update_code_heap_roots(); - } - - /* do some copying -- this is where most of the work is done */ - copy_reachable_objects(scan,¤t_gc->newspace->here); - - /* On minor GC, update literal references in code blocks, now that all - data heap objects are in their final location. On a major GC, - free all code blocks that did not get marked during tracing. */ - if(current_gc->collecting_tenured_p()) - free_unmarked_code_blocks(); - else - update_dirty_code_blocks(); - - /* GC completed without any generations filling up; finish up */ end_gc(); delete current_gc; diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index 2a74568b66..14825c054f 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -44,6 +44,11 @@ struct gc_state { return collecting_gen == data->nursery(); } + inline bool collecting_aging_p() + { + return data->have_aging_p() && collecting_gen == data->aging(); + } + inline bool collecting_tenured_p() { return collecting_gen == data->tenured(); diff --git a/vm/data_heap.hpp b/vm/data_heap.hpp index 820714ab65..59dbb0cb66 100755 --- a/vm/data_heap.hpp +++ b/vm/data_heap.hpp @@ -17,6 +17,11 @@ struct zone { end = start_ + size_; return end; } + + inline bool contains_p(object *pointer) + { + return (cell)pointer >= start && (cell)pointer < end; + } }; struct data_heap { @@ -57,9 +62,4 @@ struct data_heap { static const cell max_gen_count = 3; -inline static bool in_zone(zone *z, object *pointer) -{ - return (cell)pointer >= z->start && (cell)pointer < z->end; -} - } diff --git a/vm/generic_arrays.hpp b/vm/generic_arrays.hpp index d54fbaf468..07e876171b 100755 --- a/vm/generic_arrays.hpp +++ b/vm/generic_arrays.hpp @@ -28,7 +28,7 @@ template Array *factor_vm::allot_array_internal(cell capacity) template bool factor_vm::reallot_array_in_place_p(Array *array, cell capacity) { - return in_zone(&nursery,array) && capacity <= array_capacity(array); + return nursery.contains_p(array) && capacity <= array_capacity(array); } template Array *factor_vm::reallot_array(Array *array_, cell capacity) diff --git a/vm/strings.cpp b/vm/strings.cpp index 8c7582d35c..fa7a775760 100644 --- a/vm/strings.cpp +++ b/vm/strings.cpp @@ -108,8 +108,8 @@ void factor_vm::primitive_string() bool factor_vm::reallot_string_in_place_p(string *str, cell capacity) { - return in_zone(&nursery,str) - && (str->aux == F || in_zone(&nursery,untag(str->aux))) + return nursery.contains_p(str) + && (str->aux == F || nursery.contains_p(untag(str->aux))) && capacity <= string_capacity(str); } diff --git a/vm/vm.hpp b/vm/vm.hpp index d7099bfc37..c7176dd6ed 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -245,28 +245,34 @@ struct factor_vm void init_data_gc(); object *copy_untagged_object_impl(object *pointer, cell size); object *copy_object_impl(object *untagged); - bool should_copy_p(object *untagged); object *resolve_forwarding(object *untagged); template Type *copy_untagged_object(Type *untagged); - cell copy_object(cell pointer); - void trace_handle(cell *handle); - void trace_card(card *ptr, cell gen, cell here); - void trace_card_deck(card_deck *deck, cell gen, card mask, card unmask); - void trace_generation_cards(cell gen); - void trace_cards(); - void trace_stack_elements(segment *region, cell top); - void trace_registered_locals(); - void trace_registered_bignums(); - void trace_roots(); - void trace_contexts(); - void update_code_heap_roots(); - cell copy_next_from_nursery(cell scan); - cell copy_next_from_aging(cell scan); - cell copy_next_from_tenured(cell scan); - void copy_reachable_objects(cell scan, cell *end); + template object *resolve_forwarding(object *untagged, Strategy &strategy); + template Type *copy_untagged_object(Type *untagged, Strategy &strategy); + template cell copy_object(cell pointer, Strategy &strategy); + template void trace_handle(cell *handle, Strategy &strategy); + template void trace_card(card *ptr, cell gen, cell here, Strategy &strategy); + template void trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy); + template void trace_generation_cards(cell gen, Strategy &strategy); + template void trace_cards(Strategy &strategy); + template void trace_stack_elements(segment *region, cell top, Strategy &strategy); + template void trace_registered_locals(Strategy &strategy); + template void trace_registered_bignums(Strategy &strategy); + template void trace_roots(Strategy &strategy); + template void mark_active_blocks(context *stacks, Strategy &strategy); + template void trace_contexts(Strategy &strategy); + template void trace_literal_references(code_block *compiled, Strategy &strategy); + template void trace_code_heap_roots(Strategy &strategy); + template void mark_code_block(code_block *compiled, Strategy &strategy); + template void mark_object_code_block(object *object, Strategy &strategy); + template cell copy_next(cell scan, Strategy &strategy); + template void update_code_heap_roots(Strategy &strategy); void free_unmarked_code_blocks(); void update_dirty_code_blocks(); void begin_gc(cell requested_bytes); + void collect_nursery(); + void collect_aging(); + void collect_tenured(bool trace_contexts_); void end_gc(); void garbage_collection(cell gen, bool growing_data_heap, bool trace_contexts, cell requested_bytes); void gc(); @@ -516,13 +522,9 @@ struct factor_vm void store_address_masked(cell *ptr, fixnum value, cell mask, fixnum shift); void store_address_in_code_block(cell klass, cell offset, fixnum absolute_value); void update_literal_references(code_block *compiled); - void trace_literal_references(code_block *compiled); void relocate_code_block_step(relocation_entry rel, cell index, code_block *compiled); void update_word_references(code_block *compiled); void check_code_address(cell address); - void mark_code_block(code_block *compiled); - void mark_active_blocks(context *stacks); - void mark_object_code_block(object *object); void relocate_code_block(code_block *compiled); void fixup_labels(array *labels, code_block *compiled); code_block *allot_code_block(cell size); @@ -539,7 +541,6 @@ struct factor_vm void init_code_heap(cell size); bool in_code_heap_p(cell ptr); void jit_compile_word(cell word_, cell def_, bool relocate); - void trace_code_heap_roots(); void update_code_heap_words(); void primitive_modify_code_heap(); void primitive_code_room(); From 47c735d81d3522a74f1b0d2d17bc2bacea891db9 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 00:13:54 -0500 Subject: [PATCH 06/63] vm: more GC refactoring --- vm/data_gc.cpp | 272 +++++++++++++++++++++----------------------- vm/data_gc.hpp | 16 +++ vm/inline_cache.cpp | 4 + vm/vm.cpp | 9 +- vm/vm.hpp | 9 -- 5 files changed, 155 insertions(+), 155 deletions(-) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index dad6b9c9eb..35a5ba07de 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -17,68 +17,6 @@ gc_state::gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_ge gc_state::~gc_state() { } -/* Given a pointer to oldspace, copy it to newspace */ -object *factor_vm::copy_untagged_object_impl(object *pointer, cell size) -{ - if(current_gc->newspace->here + size >= current_gc->newspace->end) - longjmp(current_gc->gc_unwind,1); - - object *newpointer = allot_zone(current_gc->newspace,size); - - gc_stats *s = &stats[current_gc->collecting_gen]; - s->object_count++; - s->bytes_copied += size; - - memcpy(newpointer,pointer,size); - return newpointer; -} - -object *factor_vm::copy_object_impl(object *untagged) -{ - object *newpointer = copy_untagged_object_impl(untagged,untagged_object_size(untagged)); - untagged->h.forward_to(newpointer); - return newpointer; -} - -/* Follow a chain of forwarding pointers */ -template object *factor_vm::resolve_forwarding(object *untagged, Strategy &strategy) -{ - check_data_pointer(untagged); - - /* is there another forwarding pointer? */ - if(untagged->h.forwarding_pointer_p()) - return resolve_forwarding(untagged->h.forwarding_pointer(),strategy); - /* we've found the destination */ - else - { - untagged->h.check_header(); - if(strategy.should_copy_p(untagged)) - return copy_object_impl(untagged); - else - return untagged; - } -} - -template Type *factor_vm::copy_untagged_object(Type *untagged, Strategy &strategy) -{ - check_data_pointer(untagged); - - if(untagged->h.forwarding_pointer_p()) - untagged = (Type *)resolve_forwarding(untagged->h.forwarding_pointer(),strategy); - else - { - untagged->h.check_header(); - untagged = (Type *)copy_object_impl(untagged); - } - - return untagged; -} - -template cell factor_vm::copy_object(cell pointer, Strategy &strategy) -{ - return RETAG(copy_untagged_object(untag(pointer),strategy),TAG(pointer)); -} - template void factor_vm::trace_handle(cell *handle, Strategy &strategy) { cell pointer = *handle; @@ -88,7 +26,7 @@ template void factor_vm::trace_handle(cell *handle, Strategy object *obj = untag(pointer); check_data_pointer(obj); if(strategy.should_copy_p(obj)) - *handle = copy_object(pointer,strategy); + *handle = strategy.copy_object(pointer); } } @@ -247,7 +185,7 @@ template void factor_vm::trace_registered_bignums(Strategy &s { check_data_pointer(pointer); if(strategy.should_copy_p(pointer)) - *handle = copy_untagged_object(pointer,strategy); + *handle = untag(strategy.copy_object(tag(pointer))); #ifdef FACTOR_DEBUG assert((*handle)->h.hi_tag() == BIGNUM_TYPE); #endif @@ -383,15 +321,18 @@ template struct literal_reference_tracer { aging and nursery collections */ template void factor_vm::trace_code_heap_roots(Strategy &strategy) { - literal_reference_tracer tracer(this,strategy); - iterate_code_heap(tracer); + if(current_gc->collecting_gen >= last_code_heap_scan) + { + literal_reference_tracer tracer(this,strategy); + iterate_code_heap(tracer); - if(current_gc->collecting_accumulation_gen_p()) - last_code_heap_scan = current_gc->collecting_gen; - else - last_code_heap_scan = current_gc->collecting_gen + 1; - - code_heap_scans++; + if(current_gc->collecting_accumulation_gen_p()) + last_code_heap_scan = current_gc->collecting_gen; + else + last_code_heap_scan = current_gc->collecting_gen + 1; + + code_heap_scans++; + } } /* Mark all literals referenced from a word XT. Only for tenured @@ -406,37 +347,6 @@ template void factor_vm::mark_code_block(code_block *compiled trace_handle(&compiled->relocation,strategy); } -template cell factor_vm::copy_next(cell scan, Strategy &strategy) -{ - cell *obj = (cell *)scan; - cell *end = (cell *)(scan + binary_payload_start((object *)scan)); - - if(obj != end) - { - obj++; - - for(; obj < end; obj++) - trace_handle(obj,strategy); - } - - return scan + untagged_object_size((object *)scan); -} - -template void factor_vm::update_code_heap_roots(Strategy &strategy) -{ - if(current_gc->collecting_gen >= last_code_heap_scan) - { - code_heap_scans++; - - trace_code_heap_roots(strategy); - - if(current_gc->collecting_accumulation_gen_p()) - last_code_heap_scan = current_gc->collecting_gen; - else - last_code_heap_scan = current_gc->collecting_gen + 1; - } -} - struct literal_and_word_reference_updater { factor_vm *myvm; @@ -502,12 +412,107 @@ void factor_vm::begin_gc(cell requested_bytes) } } -struct nursery_collector +template +copying_collector::copying_collector(factor_vm *myvm_) +: myvm(myvm_), current_gc(myvm_->current_gc) { - factor_vm *myvm; + scan = current_gc->newspace->here; +} + +template Strategy ©ing_collector::strategy() +{ + return static_cast(*this); +} + +/* Given a pointer to oldspace, copy it to newspace */ +template object *copying_collector::copy_untagged_object_impl(object *pointer, cell size) +{ + if(current_gc->newspace->here + size >= current_gc->newspace->end) + longjmp(current_gc->gc_unwind,1); + + object *newpointer = myvm->allot_zone(current_gc->newspace,size); + + gc_stats *s = &myvm->stats[current_gc->collecting_gen]; + s->object_count++; + s->bytes_copied += size; + + memcpy(newpointer,pointer,size); + return newpointer; +} + +template object *copying_collector::copy_object_impl(object *untagged) +{ + object *newpointer = copy_untagged_object_impl(untagged,myvm->untagged_object_size(untagged)); + untagged->h.forward_to(newpointer); + return newpointer; +} + +/* Follow a chain of forwarding pointers */ +template object *copying_collector::resolve_forwarding(object *untagged) +{ + myvm->check_data_pointer(untagged); + + /* is there another forwarding pointer? */ + if(untagged->h.forwarding_pointer_p()) + return resolve_forwarding(untagged->h.forwarding_pointer()); + /* we've found the destination */ + else + { + untagged->h.check_header(); + if(should_copy_p(untagged)) + return copy_object_impl(untagged); + else + return untagged; + } +} + +template cell copying_collector::copy_object(cell pointer) +{ + object *untagged = myvm->untag(pointer); + + myvm->check_data_pointer(untagged); + + if(untagged->h.forwarding_pointer_p()) + untagged = resolve_forwarding(untagged->h.forwarding_pointer()); + else + { + untagged->h.check_header(); + untagged = copy_object_impl(untagged); + } + + return RETAG(untagged,TAG(pointer)); +} + +template bool copying_collector::should_copy_p(object *pointer) +{ + return strategy().should_copy_p(pointer); +} + +template cell copying_collector::copy_next(cell scan) +{ + cell *obj = (cell *)scan; + cell *end = (cell *)(scan + myvm->binary_payload_start((object *)scan)); + + if(obj != end) + { + obj++; + + for(; obj < end; obj++) + myvm->trace_handle(obj,strategy()); + } + + return scan + myvm->untagged_object_size((object *)scan); +} + +template void copying_collector::go() +{ + strategy().copy_reachable_objects(scan,¤t_gc->newspace->here); +} + +struct nursery_collector : copying_collector +{ + explicit nursery_collector(factor_vm *myvm_) : copying_collector(myvm_) {} - explicit nursery_collector(factor_vm *myvm_) : myvm(myvm_) {} - bool should_copy_p(object *untagged) { if(myvm->current_gc->newspace->contains_p(untagged)) @@ -515,11 +520,10 @@ struct nursery_collector else return myvm->nursery.contains_p(untagged); } - + void copy_reachable_objects(cell scan, cell *end) { - while(scan < myvm->current_gc->newspace->here) - scan = myvm->copy_next(scan,*this); + while(scan < *end) scan = copy_next(scan); } }; @@ -527,26 +531,18 @@ void factor_vm::collect_nursery() { nursery_collector collector(this); - cell scan = current_gc->newspace->here; - trace_roots(collector); trace_contexts(collector); trace_cards(collector); - - if(current_gc->collecting_gen >= last_code_heap_scan) - update_code_heap_roots(collector); - - collector.copy_reachable_objects(scan,¤t_gc->newspace->here); - + trace_code_heap_roots(collector); + collector.go(); update_dirty_code_blocks(); } -struct aging_collector +struct aging_collector : copying_collector { - factor_vm *myvm; + explicit aging_collector(factor_vm *myvm_) : copying_collector(myvm_) {} - explicit aging_collector(factor_vm *myvm_) : myvm(myvm_) {} - bool should_copy_p(object *untagged) { if(myvm->current_gc->newspace->contains_p(untagged)) @@ -557,8 +553,7 @@ struct aging_collector void copy_reachable_objects(cell scan, cell *end) { - while(scan < myvm->current_gc->newspace->here) - scan = myvm->copy_next(scan,*this); + while(scan < *end) scan = copy_next(scan); } }; @@ -566,25 +561,17 @@ void factor_vm::collect_aging() { aging_collector collector(this); - cell scan = current_gc->newspace->here; - trace_roots(collector); trace_contexts(collector); trace_cards(collector); - - if(current_gc->collecting_gen >= last_code_heap_scan) - update_code_heap_roots(collector); - - collector.copy_reachable_objects(scan,¤t_gc->newspace->here); - + trace_code_heap_roots(collector); + collector.go(); update_dirty_code_blocks(); } -struct tenured_collector +struct tenured_collector : copying_collector { - factor_vm *myvm; - - explicit tenured_collector(factor_vm *myvm_) : myvm(myvm_) {} + explicit tenured_collector(factor_vm *myvm_) : copying_collector(myvm_) {} bool should_copy_p(object *untagged) { @@ -593,10 +580,10 @@ struct tenured_collector void copy_reachable_objects(cell scan, cell *end) { - while(scan < myvm->current_gc->newspace->here) + while(scan < *end) { myvm->mark_object_code_block(myvm->untag(scan),*this); - scan = myvm->copy_next(scan,*this); + scan = copy_next(scan); } } }; @@ -605,14 +592,9 @@ void factor_vm::collect_tenured(bool trace_contexts_) { tenured_collector collector(this); - cell scan = current_gc->newspace->here; - trace_roots(collector); - if(trace_contexts_) - trace_contexts(collector); - - collector.copy_reachable_objects(scan,¤t_gc->newspace->here); - + if(trace_contexts_) trace_contexts(collector); + collector.go(); free_unmarked_code_blocks(); } diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index 14825c054f..95c7249823 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -63,6 +63,22 @@ struct gc_state { } }; +template struct copying_collector { + factor_vm *myvm; + gc_state *current_gc; + cell scan; + + explicit copying_collector(factor_vm *myvm_); + Strategy &strategy(); + object *copy_untagged_object_impl(object *pointer, cell size); + cell copy_next(cell scan); + object *copy_object_impl(object *untagged); + object *resolve_forwarding(object *untagged); + cell copy_object(cell pointer); + bool should_copy_p(object *pointer); + void go(); +}; + VM_C_API void inline_gc(cell *gc_roots_base, cell gc_roots_size, factor_vm *myvm); } diff --git a/vm/inline_cache.cpp b/vm/inline_cache.cpp index e278c0d461..1626af1965 100755 --- a/vm/inline_cache.cpp +++ b/vm/inline_cache.cpp @@ -6,6 +6,10 @@ namespace factor void factor_vm::init_inline_caching(int max_size) { max_pic_size = max_size; + cold_call_to_ic_transitions = 0; + ic_to_pic_transitions = 0; + pic_to_mega_transitions = 0; + for(int i = 0; i < 4; i++) pic_counts[i] = 0; } void factor_vm::deallocate_inline_cache(cell return_address) diff --git a/vm/vm.cpp b/vm/vm.cpp index 45cf05075c..15df6cc18a 100755 --- a/vm/vm.cpp +++ b/vm/vm.cpp @@ -3,6 +3,13 @@ namespace factor { -factor_vm::factor_vm() { } +factor_vm::factor_vm() : + profiling_p(false), + secure_gc(false), + gc_off(false), + current_gc(NULL), + fep_disabled(false), + full_output(false) + { } } diff --git a/vm/vm.hpp b/vm/vm.hpp index c7176dd6ed..ad0931112e 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -243,13 +243,6 @@ struct factor_vm cell last_code_heap_scan; void init_data_gc(); - object *copy_untagged_object_impl(object *pointer, cell size); - object *copy_object_impl(object *untagged); - object *resolve_forwarding(object *untagged); - template Type *copy_untagged_object(Type *untagged); - template object *resolve_forwarding(object *untagged, Strategy &strategy); - template Type *copy_untagged_object(Type *untagged, Strategy &strategy); - template cell copy_object(cell pointer, Strategy &strategy); template void trace_handle(cell *handle, Strategy &strategy); template void trace_card(card *ptr, cell gen, cell here, Strategy &strategy); template void trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy); @@ -265,8 +258,6 @@ struct factor_vm template void trace_code_heap_roots(Strategy &strategy); template void mark_code_block(code_block *compiled, Strategy &strategy); template void mark_object_code_block(object *object, Strategy &strategy); - template cell copy_next(cell scan, Strategy &strategy); - template void update_code_heap_roots(Strategy &strategy); void free_unmarked_code_blocks(); void update_dirty_code_blocks(); void begin_gc(cell requested_bytes); From d10e27149c5b01039eaeb7b074a22d6fc5652e2f Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 01:42:17 -0500 Subject: [PATCH 07/63] vm: cleanup --- vm/code_block.cpp | 2 +- vm/code_heap.cpp | 20 ++++++++++++++++---- vm/code_heap.hpp | 23 ++++++++--------------- vm/data_gc.cpp | 10 +++++----- vm/heap.cpp | 5 ++--- vm/heap.hpp | 5 +++-- vm/master.hpp | 2 +- vm/profiler.cpp | 4 +--- vm/quotations.cpp | 4 +--- vm/vm.hpp | 16 ++++++++-------- 10 files changed, 46 insertions(+), 45 deletions(-) diff --git a/vm/code_block.cpp b/vm/code_block.cpp index ab69ee8ca1..ec7da8af9f 100755 --- a/vm/code_block.cpp +++ b/vm/code_block.cpp @@ -466,7 +466,7 @@ code_block *factor_vm::add_code_block(cell type, cell code_, cell labels_, cell /* next time we do a minor GC, we have to scan the code heap for literals */ - last_code_heap_scan = data->nursery(); + this->code->last_code_heap_scan = data->nursery(); return compiled; } diff --git a/vm/code_heap.cpp b/vm/code_heap.cpp index e44cbeba17..a0ad1a7dd0 100755 --- a/vm/code_heap.cpp +++ b/vm/code_heap.cpp @@ -3,10 +3,12 @@ namespace factor { +code_heap::code_heap(factor_vm *myvm, cell size) : heap(myvm,size) {} + /* Allocate a code heap during startup */ void factor_vm::init_code_heap(cell size) { - code = new heap(this,size); + code = new code_heap(this,size); } bool factor_vm::in_code_heap_p(cell ptr) @@ -28,6 +30,16 @@ void factor_vm::jit_compile_word(cell word_, cell def_, bool relocate) if(word->pic_tail_def != F) jit_compile(word->pic_tail_def,relocate); } +struct word_updater { + factor_vm *myvm; + + explicit word_updater(factor_vm *myvm_) : myvm(myvm_) {} + void operator()(code_block *compiled) + { + myvm->update_word_references(compiled); + } +}; + /* Update pointers to words referenced from all code blocks. Only after defining a new word. */ void factor_vm::update_code_heap_words() @@ -100,7 +112,7 @@ void factor_vm::primitive_code_room() code_block *factor_vm::forward_xt(code_block *compiled) { - return (code_block *)forwarding[compiled]; + return (code_block *)code->forwarding[compiled]; } struct xt_forwarder { @@ -199,13 +211,13 @@ void factor_vm::compact_code_heap() garbage_collection(data->tenured(),false,false,0); /* Figure out where the code heap blocks are going to end up */ - cell size = code->compute_heap_forwarding(forwarding); + cell size = code->compute_heap_forwarding(); /* Update word and quotation code pointers */ forward_object_xts(); /* Actually perform the compaction */ - code->compact_heap(forwarding); + code->compact_heap(); /* Update word and quotation XTs */ fixup_object_xts(); diff --git a/vm/code_heap.hpp b/vm/code_heap.hpp index a746d7a445..c0b6d9d1cf 100755 --- a/vm/code_heap.hpp +++ b/vm/code_heap.hpp @@ -1,21 +1,14 @@ namespace factor { -inline void factor_vm::check_code_pointer(cell ptr) -{ -#ifdef FACTOR_DEBUG - assert(in_code_heap_p(ptr)); -#endif -} - -struct word_updater { - factor_vm *myvm; - - explicit word_updater(factor_vm *myvm_) : myvm(myvm_) {} - void operator()(code_block *compiled) - { - myvm->update_word_references(compiled); - } +struct code_heap : heap { + /* What generation was being collected when trace_code_heap_roots() was last + called? Until the next call to add_code_block(), future + collections of younger generations don't have to touch the code + heap. */ + cell last_code_heap_scan; + + explicit code_heap(factor_vm *myvm, cell size); }; } diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 35a5ba07de..291c5094d7 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -5,7 +5,7 @@ namespace factor void factor_vm::init_data_gc() { - last_code_heap_scan = data->nursery(); + code->last_code_heap_scan = data->nursery(); } gc_state::gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_gen_) : @@ -321,15 +321,15 @@ template struct literal_reference_tracer { aging and nursery collections */ template void factor_vm::trace_code_heap_roots(Strategy &strategy) { - if(current_gc->collecting_gen >= last_code_heap_scan) + if(current_gc->collecting_gen >= code->last_code_heap_scan) { literal_reference_tracer tracer(this,strategy); iterate_code_heap(tracer); if(current_gc->collecting_accumulation_gen_p()) - last_code_heap_scan = current_gc->collecting_gen; + code->last_code_heap_scan = current_gc->collecting_gen; else - last_code_heap_scan = current_gc->collecting_gen + 1; + code->last_code_heap_scan = current_gc->collecting_gen + 1; code_heap_scans++; } @@ -364,7 +364,7 @@ void factor_vm::free_unmarked_code_blocks() { literal_and_word_reference_updater updater(this); code->free_unmarked(updater); - last_code_heap_scan = current_gc->collecting_gen; + code->last_code_heap_scan = current_gc->collecting_gen; } void factor_vm::update_dirty_code_blocks() diff --git a/vm/heap.cpp b/vm/heap.cpp index 5bd8608f3d..91ebc291cd 100644 --- a/vm/heap.cpp +++ b/vm/heap.cpp @@ -96,7 +96,6 @@ void heap::assert_free_block(free_heap_block *block) myvm->critical_error("Invalid block in free list",(cell)block); } - free_heap_block *heap::find_free_block(cell size) { cell attempt = size; @@ -254,7 +253,7 @@ cell heap::heap_size() } /* Compute where each block is going to go, after compaction */ -cell heap::compute_heap_forwarding(unordered_map &forwarding) +cell heap::compute_heap_forwarding() { heap_block *scan = first_block(); char *address = (char *)first_block(); @@ -275,7 +274,7 @@ cell heap::compute_heap_forwarding(unordered_map &forwardin return (cell)address - seg->start; } -void heap::compact_heap(unordered_map &forwarding) +void heap::compact_heap() { heap_block *scan = first_block(); diff --git a/vm/heap.hpp b/vm/heap.hpp index 2558338f59..d878072057 100644 --- a/vm/heap.hpp +++ b/vm/heap.hpp @@ -13,6 +13,7 @@ struct heap { factor_vm *myvm; segment *seg; heap_free_list free; + unordered_map forwarding; explicit heap(factor_vm *myvm, cell size); @@ -48,8 +49,8 @@ struct heap { void unmark_marked(); void heap_usage(cell *used, cell *total_free, cell *max_free); cell heap_size(); - cell compute_heap_forwarding(unordered_map &forwarding); - void compact_heap(unordered_map &forwarding); + cell compute_heap_forwarding(); + void compact_heap(); heap_block *free_allocated(heap_block *prev, heap_block *scan); diff --git a/vm/master.hpp b/vm/master.hpp index 103387ad4b..0e34144099 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -76,6 +76,7 @@ namespace factor #include "heap.hpp" #include "image.hpp" #include "alien.hpp" +#include "code_heap.hpp" #include "vm.hpp" #include "tagged.hpp" #include "local_roots.hpp" @@ -84,7 +85,6 @@ namespace factor #include "arrays.hpp" #include "math.hpp" #include "booleans.hpp" -#include "code_heap.hpp" #include "byte_arrays.hpp" #include "jit.hpp" #include "quotations.hpp" diff --git a/vm/profiler.cpp b/vm/profiler.cpp index e61c10f293..228b163f83 100755 --- a/vm/profiler.cpp +++ b/vm/profiler.cpp @@ -43,9 +43,7 @@ void factor_vm::set_profiling(bool profiling) update_word_xt(word.value()); } - /* Update XTs in code heap */ - word_updater updater(this); - iterate_code_heap(updater); + update_code_heap_words(); } void factor_vm::primitive_profiling() diff --git a/vm/quotations.cpp b/vm/quotations.cpp index f8a9a7183b..a77b22844b 100755 --- a/vm/quotations.cpp +++ b/vm/quotations.cpp @@ -343,9 +343,7 @@ void factor_vm::compile_all_words() } - /* Update XTs in code heap */ - word_updater updater(this); - iterate_code_heap(updater); + update_code_heap_words(); } /* Allocates memory */ diff --git a/vm/vm.hpp b/vm/vm.hpp index ad0931112e..ce45a6122d 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -236,11 +236,6 @@ struct factor_vm u64 decks_scanned; u64 card_scan_time; cell code_heap_scans; - /* What generation was being collected when trace_code_heap_roots() was last - called? Until the next call to add_code_block(), future - collections of younger generations don't have to touch the code - heap. */ - cell last_code_heap_scan; void init_data_gc(); template void trace_handle(cell *handle, Strategy &strategy); @@ -526,8 +521,14 @@ struct factor_vm } //code_heap - heap *code; - unordered_map forwarding; + code_heap *code; + + inline void check_code_pointer(cell ptr) + { + #ifdef FACTOR_DEBUG + assert(in_code_heap_p(ptr)); + #endif + } void init_code_heap(cell size); bool in_code_heap_p(cell ptr); @@ -539,7 +540,6 @@ struct factor_vm void forward_object_xts(); void fixup_object_xts(); void compact_code_heap(); - inline void check_code_pointer(cell ptr); /* Apply a function to every code block */ template void iterate_code_heap(Iterator &iter) From b50d3f3fb0e61246ab09d4929f204418581e9a29 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 02:39:12 -0500 Subject: [PATCH 08/63] vm: number of generations is not configurable anymore, split up begin_gc() and end_gc() into collect_{nursery,aging,aging_again,tenured}() --- vm/data_gc.cpp | 221 ++++++++++++++++++++++++----------------------- vm/data_gc.hpp | 16 ++-- vm/data_heap.cpp | 35 ++------ vm/data_heap.hpp | 12 +-- vm/debug.cpp | 4 +- vm/factor.cpp | 3 - vm/image.cpp | 3 +- vm/image.hpp | 2 +- vm/master.hpp | 3 +- vm/vm.hpp | 10 +-- 10 files changed, 143 insertions(+), 166 deletions(-) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 291c5094d7..19a740ac70 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -74,7 +74,7 @@ template void factor_vm::trace_card_deck(card_deck *deck, cel decks_scanned++; } -/* Copy all newspace objects referenced from marked cards to the destination */ +/* Trace all objects referenced from marked cards */ template void factor_vm::trace_generation_cards(cell gen, Strategy &strategy) { card_deck *first_deck = addr_to_deck(data->generations[gen].start); @@ -95,7 +95,7 @@ template void factor_vm::trace_generation_cards(cell gen, Str unmask = card_points_to_nursery; /* after the collection, all cards in aging space can be cleared */ - else if(data->have_aging_p() && gen == data->aging()) + else if(gen == data->aging()) unmask = card_mark_mask; else { @@ -106,7 +106,7 @@ template void factor_vm::trace_generation_cards(cell gen, Str /* if we are collecting aging space into tenured space, we care about all old->nursery and old->aging pointers. no old->aging pointers can remain */ - else if(data->have_aging_p() && current_gc->collecting_gen == data->aging()) + else if(current_gc->collecting_aging_p()) { if(current_gc->collecting_aging_again) { @@ -147,7 +147,7 @@ template void factor_vm::trace_cards(Strategy &strategy) u64 start = current_micros(); cell i; - for(i = current_gc->collecting_gen + 1; i < data->gen_count; i++) + for(i = current_gc->collecting_gen + 1; i < gen_count; i++) trace_generation_cards(i,strategy); card_scan_time += (current_micros() - start); @@ -284,8 +284,7 @@ template void factor_vm::trace_contexts(Strategy &strategy) } } -/* Copy all literals referenced from a code block to newspace. Only for -aging and nursery collections */ +/* Trace all literals referenced from a code block. Only for aging and nursery collections */ template void factor_vm::trace_literal_references(code_block *compiled, Strategy &strategy) { if(current_gc->collecting_gen >= compiled->last_scan) @@ -317,8 +316,7 @@ template struct literal_reference_tracer { } }; -/* Copy literals referenced from all code blocks to newspace. Only for -aging and nursery collections */ +/* Trace literals referenced from all code blocks. Only for aging and nursery collections */ template void factor_vm::trace_code_heap_roots(Strategy &strategy) { if(current_gc->collecting_gen >= code->last_code_heap_scan) @@ -379,44 +377,11 @@ void factor_vm::update_dirty_code_blocks() dirty_code_blocks.clear(); } -/* Prepare to start copying reachable objects into an unused zone */ -void factor_vm::begin_gc(cell requested_bytes) -{ - if(current_gc->growing_data_heap) - { - assert(current_gc->collecting_tenured_p()); - - current_gc->old_data_heap = data; - set_data_heap(grow_data_heap(current_gc->old_data_heap,requested_bytes)); - current_gc->newspace = &data->generations[data->tenured()]; - } - else if(current_gc->collecting_accumulation_gen_p()) - { - /* when collecting one of these generations, rotate it - with the semispace */ - zone z = data->generations[current_gc->collecting_gen]; - data->generations[current_gc->collecting_gen] = data->semispaces[current_gc->collecting_gen]; - data->semispaces[current_gc->collecting_gen] = z; - reset_generation(current_gc->collecting_gen); - current_gc->newspace = &data->generations[current_gc->collecting_gen]; - clear_cards(current_gc->collecting_gen,current_gc->collecting_gen); - clear_decks(current_gc->collecting_gen,current_gc->collecting_gen); - clear_allot_markers(current_gc->collecting_gen,current_gc->collecting_gen); - } - else - { - /* when collecting a younger generation, we copy - reachable objects to the next oldest generation, - so we set the newspace so the next generation. */ - current_gc->newspace = &data->generations[current_gc->collecting_gen + 1]; - } -} - template -copying_collector::copying_collector(factor_vm *myvm_) -: myvm(myvm_), current_gc(myvm_->current_gc) +copying_collector::copying_collector(factor_vm *myvm_, zone *newspace_) +: myvm(myvm_), current_gc(myvm_->current_gc), newspace(newspace_) { - scan = current_gc->newspace->here; + scan = newspace->here; } template Strategy ©ing_collector::strategy() @@ -427,10 +392,10 @@ template Strategy ©ing_collector::strategy() /* Given a pointer to oldspace, copy it to newspace */ template object *copying_collector::copy_untagged_object_impl(object *pointer, cell size) { - if(current_gc->newspace->here + size >= current_gc->newspace->end) + if(newspace->here + size >= newspace->end) longjmp(current_gc->gc_unwind,1); - object *newpointer = myvm->allot_zone(current_gc->newspace,size); + object *newpointer = myvm->allot_zone(newspace,size); gc_stats *s = &myvm->stats[current_gc->collecting_gen]; s->object_count++; @@ -488,7 +453,7 @@ template bool copying_collector::should_copy_p(obje return strategy().should_copy_p(pointer); } -template cell copying_collector::copy_next(cell scan) +template cell copying_collector::trace_next(cell scan) { cell *obj = (cell *)scan; cell *end = (cell *)(scan + myvm->binary_payload_start((object *)scan)); @@ -506,16 +471,17 @@ template cell copying_collector::copy_next(cell sca template void copying_collector::go() { - strategy().copy_reachable_objects(scan,¤t_gc->newspace->here); + strategy().copy_reachable_objects(scan,&newspace->here); } struct nursery_collector : copying_collector { - explicit nursery_collector(factor_vm *myvm_) : copying_collector(myvm_) {} + explicit nursery_collector(factor_vm *myvm_, zone *newspace_) : + copying_collector(myvm_,newspace_) {} bool should_copy_p(object *untagged) { - if(myvm->current_gc->newspace->contains_p(untagged)) + if(newspace->contains_p(untagged)) return false; else return myvm->nursery.contains_p(untagged); @@ -523,29 +489,18 @@ struct nursery_collector : copying_collector void copy_reachable_objects(cell scan, cell *end) { - while(scan < *end) scan = copy_next(scan); + while(scan < *end) scan = trace_next(scan); } }; -void factor_vm::collect_nursery() -{ - nursery_collector collector(this); - - trace_roots(collector); - trace_contexts(collector); - trace_cards(collector); - trace_code_heap_roots(collector); - collector.go(); - update_dirty_code_blocks(); -} - struct aging_collector : copying_collector { - explicit aging_collector(factor_vm *myvm_) : copying_collector(myvm_) {} + explicit aging_collector(factor_vm *myvm_, zone *newspace_) : + copying_collector(myvm_,newspace_) {} bool should_copy_p(object *untagged) { - if(myvm->current_gc->newspace->contains_p(untagged)) + if(newspace->contains_p(untagged)) return false; else return !myvm->data->generations[myvm->data->tenured()].contains_p(untagged); @@ -553,29 +508,34 @@ struct aging_collector : copying_collector void copy_reachable_objects(cell scan, cell *end) { - while(scan < *end) scan = copy_next(scan); + while(scan < *end) scan = trace_next(scan); } }; -void factor_vm::collect_aging() +struct aging_again_collector : copying_collector { - aging_collector collector(this); + explicit aging_again_collector(factor_vm *myvm_, zone *newspace_) : + copying_collector(myvm_,newspace_) {} - trace_roots(collector); - trace_contexts(collector); - trace_cards(collector); - trace_code_heap_roots(collector); - collector.go(); - update_dirty_code_blocks(); -} + bool should_copy_p(object *untagged) + { + return !newspace->contains_p(untagged); + } + + void copy_reachable_objects(cell scan, cell *end) + { + while(scan < *end) scan = trace_next(scan); + } +}; struct tenured_collector : copying_collector { - explicit tenured_collector(factor_vm *myvm_) : copying_collector(myvm_) {} + explicit tenured_collector(factor_vm *myvm_, zone *newspace_) : + copying_collector(myvm_,newspace_) {} bool should_copy_p(object *untagged) { - return !myvm->current_gc->newspace->contains_p(untagged); + return !newspace->contains_p(untagged); } void copy_reachable_objects(cell scan, cell *end) @@ -583,22 +543,83 @@ struct tenured_collector : copying_collector while(scan < *end) { myvm->mark_object_code_block(myvm->untag(scan),*this); - scan = copy_next(scan); + scan = trace_next(scan); } } }; -void factor_vm::collect_tenured(bool trace_contexts_) +void factor_vm::collect_nursery() { - tenured_collector collector(this); + nursery_collector collector(this,&data->generations[data->aging()]); + + trace_roots(collector); + trace_contexts(collector); + trace_cards(collector); + trace_code_heap_roots(collector); + collector.go(); + update_dirty_code_blocks(); + + nursery.here = nursery.start; +} + +void factor_vm::collect_aging() +{ + std::swap(data->generations[data->aging()],data->semispaces[data->aging()]); + reset_generations(data->aging(),data->aging()); + + aging_collector collector(this,&data->generations[data->aging()]); + + trace_roots(collector); + trace_contexts(collector); + trace_cards(collector); + trace_code_heap_roots(collector); + collector.go(); + update_dirty_code_blocks(); + + reset_generations(data->nursery(),data->nursery()); +} + +void factor_vm::collect_aging_again() +{ + aging_again_collector collector(this,&data->generations[data->tenured()]); + + trace_roots(collector); + trace_contexts(collector); + trace_cards(collector); + trace_code_heap_roots(collector); + collector.go(); + update_dirty_code_blocks(); + + reset_generations(data->nursery(),data->aging()); +} + +void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_) +{ + if(current_gc->growing_data_heap) + { + current_gc->old_data_heap = data; + set_data_heap(grow_data_heap(current_gc->old_data_heap,requested_bytes)); + } + else + { + std::swap(data->generations[data->tenured()],data->semispaces[data->tenured()]); + reset_generations(data->tenured(),data->tenured()); + } + + tenured_collector collector(this,&data->generations[data->tenured()]); trace_roots(collector); if(trace_contexts_) trace_contexts(collector); collector.go(); free_unmarked_code_blocks(); + + reset_generations(data->nursery(),data->aging()); + + if(current_gc->growing_data_heap) + delete current_gc->old_data_heap; } -void factor_vm::end_gc() +void factor_vm::record_gc_stats() { gc_stats *s = &stats[current_gc->collecting_gen]; @@ -607,24 +628,6 @@ void factor_vm::end_gc() s->gc_time += gc_elapsed; if(s->max_gc_time < gc_elapsed) s->max_gc_time = gc_elapsed; - - if(current_gc->growing_data_heap) - delete current_gc->old_data_heap; - - if(current_gc->collecting_nursery_p()) - { - nursery.here = nursery.start; - } - else if(current_gc->collecting_accumulation_gen_p()) - { - reset_generations(data->nursery(),current_gc->collecting_gen - 1); - } - else - { - /* all generations up to and including the one - collected are now empty */ - reset_generations(data->nursery(),current_gc->collecting_gen); - } } /* Collect gen and all younger generations. @@ -657,8 +660,7 @@ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_ } /* we try collecting aging space twice before going on to collect tenured */ - else if(data->have_aging_p() - && current_gc->collecting_gen == data->aging() + else if(current_gc->collecting_aging_p() && !current_gc->collecting_aging_again) { current_gc->collecting_aging_again = true; @@ -670,16 +672,19 @@ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_ } } - begin_gc(requested_bytes); - if(current_gc->collecting_nursery_p()) collect_nursery(); else if(current_gc->collecting_aging_p()) - collect_aging(); + { + if(current_gc->collecting_aging_again) + collect_aging_again(); + else + collect_aging(); + } else if(current_gc->collecting_tenured_p()) - collect_tenured(trace_contexts_); + collect_tenured(requested_bytes,trace_contexts_); - end_gc(); + record_gc_stats(); delete current_gc; current_gc = NULL; @@ -702,7 +707,7 @@ void factor_vm::primitive_gc_stats() cell i; u64 total_gc_time = 0; - for(i = 0; i < max_gen_count; i++) + for(i = 0; i < gen_count; i++) { gc_stats *s = &stats[i]; result.add(allot_cell(s->collections)); @@ -727,7 +732,7 @@ void factor_vm::primitive_gc_stats() void factor_vm::clear_gc_stats() { - for(cell i = 0; i < max_gen_count; i++) + for(cell i = 0; i < gen_count; i++) memset(&stats[i],0,sizeof(gc_stats)); cards_scanned = 0; diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index 95c7249823..80c7cd9a01 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -14,9 +14,6 @@ struct gc_state { /* The data heap we're collecting */ data_heap *data; - /* New objects are copied here */ - zone *newspace; - /* sometimes we grow the heap */ bool growing_data_heap; data_heap *old_data_heap; @@ -46,7 +43,7 @@ struct gc_state { inline bool collecting_aging_p() { - return data->have_aging_p() && collecting_gen == data->aging(); + return collecting_gen == data->aging(); } inline bool collecting_tenured_p() @@ -56,22 +53,21 @@ struct gc_state { inline bool collecting_accumulation_gen_p() { - return ((data->have_aging_p() - && collecting_gen == data->aging() - && !collecting_aging_again) - || collecting_gen == data->tenured()); + return ((collecting_aging_p() && !collecting_aging_again) + || collecting_tenured_p()); } }; template struct copying_collector { factor_vm *myvm; gc_state *current_gc; + zone *newspace; cell scan; - explicit copying_collector(factor_vm *myvm_); + explicit copying_collector(factor_vm *myvm_, zone *newspace); Strategy &strategy(); object *copy_untagged_object_impl(object *pointer, cell size); - cell copy_next(cell scan); + cell trace_next(cell scan); object *copy_object_impl(object *untagged); object *resolve_forwarding(object *untagged); cell copy_object(cell pointer); diff --git a/vm/data_heap.cpp b/vm/data_heap.cpp index 20952736d2..d43d70e963 100755 --- a/vm/data_heap.cpp +++ b/vm/data_heap.cpp @@ -11,7 +11,7 @@ void factor_vm::init_card_decks() decks_offset = (cell)data->decks - (start >> deck_bits); } -data_heap::data_heap(factor_vm *myvm, cell gen_count_, cell young_size_, cell aging_size_, cell tenured_size_) +data_heap::data_heap(factor_vm *myvm, cell young_size_, cell aging_size_, cell tenured_size_) { young_size_ = align(young_size_,deck_size); aging_size_ = align(aging_size_,deck_size); @@ -20,18 +20,8 @@ data_heap::data_heap(factor_vm *myvm, cell gen_count_, cell young_size_, cell ag young_size = young_size_; aging_size = aging_size_; tenured_size = tenured_size_; - gen_count = gen_count_; - cell total_size; - if(gen_count == 2) - total_size = young_size + 2 * tenured_size; - else if(gen_count == 3) - total_size = young_size + 2 * aging_size + 2 * tenured_size; - else - { - total_size = 0; - fatal_error("Invalid number of generations",gen_count); - } + cell total_size = young_size + 2 * aging_size + 2 * tenured_size; total_size += deck_size; @@ -56,17 +46,11 @@ data_heap::data_heap(factor_vm *myvm, cell gen_count_, cell young_size_, cell ag alloter = generations[tenured()].init_zone(tenured_size,alloter); alloter = semispaces[tenured()].init_zone(tenured_size,alloter); - if(gen_count == 3) - { - alloter = generations[aging()].init_zone(aging_size,alloter); - alloter = semispaces[aging()].init_zone(aging_size,alloter); - } + alloter = generations[aging()].init_zone(aging_size,alloter); + alloter = semispaces[aging()].init_zone(aging_size,alloter); - if(gen_count >= 2) - { - alloter = generations[nursery()].init_zone(young_size,alloter); - alloter = semispaces[nursery()].init_zone(0,alloter); - } + alloter = generations[nursery()].init_zone(young_size,alloter); + alloter = semispaces[nursery()].init_zone(0,alloter); if(seg->end - alloter > deck_size) myvm->critical_error("Bug in alloc_data_heap",alloter); @@ -77,7 +61,6 @@ data_heap *factor_vm::grow_data_heap(data_heap *data, cell requested_bytes) cell new_tenured_size = (data->tenured_size * 2) + requested_bytes; return new data_heap(this, - data->gen_count, data->young_size, data->aging_size, new_tenured_size); @@ -149,9 +132,9 @@ void factor_vm::set_data_heap(data_heap *data_) clear_allot_markers(data->nursery(),data->tenured()); } -void factor_vm::init_data_heap(cell gens,cell young_size,cell aging_size,cell tenured_size,bool secure_gc_) +void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_) { - set_data_heap(new data_heap(this,gens,young_size,aging_size,tenured_size)); + set_data_heap(new data_heap(this,young_size,aging_size,tenured_size)); secure_gc = secure_gc_; init_data_gc(); } @@ -257,7 +240,7 @@ void factor_vm::primitive_data_room() growable_array a(this); cell gen; - for(gen = 0; gen < data->gen_count; gen++) + for(gen = 0; gen < gen_count; gen++) { zone *z = (gen == data->nursery() ? &nursery : &data->generations[gen]); a.add(tag_fixnum((z->end - z->here) >> 10)); diff --git a/vm/data_heap.hpp b/vm/data_heap.hpp index 59dbb0cb66..af7035b7d5 100755 --- a/vm/data_heap.hpp +++ b/vm/data_heap.hpp @@ -31,8 +31,6 @@ struct data_heap { cell aging_size; cell tenured_size; - cell gen_count; - zone *generations; zone *semispaces; @@ -49,17 +47,15 @@ struct data_heap { cell nursery() { return 0; } /* where objects hang around */ - cell aging() { return gen_count - 2; } + cell aging() { return 1; } /* the oldest generation */ - cell tenured() { return gen_count - 1; } + cell tenured() { return 2; } - bool have_aging_p() { return gen_count > 2; } - - explicit data_heap(factor_vm *myvm, cell gen_count, cell young_size, cell aging_size, cell tenured_size); + explicit data_heap(factor_vm *myvm, cell young_size, cell aging_size, cell tenured_size); ~data_heap(); }; -static const cell max_gen_count = 3; +static const cell gen_count = 3; } diff --git a/vm/debug.cpp b/vm/debug.cpp index 117b35af18..70d5b27766 100755 --- a/vm/debug.cpp +++ b/vm/debug.cpp @@ -225,13 +225,13 @@ void factor_vm::dump_generations() print_string("Nursery: "); dump_zone(&nursery); - for(i = 1; i < data->gen_count; i++) + for(i = 1; i < gen_count; i++) { print_string("Generation "); print_cell(i); print_string(": "); dump_zone(&data->generations[i]); } - for(i = 0; i < data->gen_count; i++) + for(i = 0; i < gen_count; i++) { print_string("Semispace "); print_cell(i); print_string(": "); dump_zone(&data->semispaces[i]); diff --git a/vm/factor.cpp b/vm/factor.cpp index 77c2e67148..9ade30318c 100755 --- a/vm/factor.cpp +++ b/vm/factor.cpp @@ -21,7 +21,6 @@ void factor_vm::default_parameters(vm_parameters *p) p->ds_size = 8 * sizeof(cell); p->rs_size = 8 * sizeof(cell); - p->gen_count = 2; p->code_size = 4; p->young_size = 1; p->aging_size = 1; @@ -30,7 +29,6 @@ void factor_vm::default_parameters(vm_parameters *p) p->ds_size = 32 * sizeof(cell); p->rs_size = 32 * sizeof(cell); - p->gen_count = 3; p->code_size = 8 * sizeof(cell); p->young_size = sizeof(cell) / 4; p->aging_size = sizeof(cell) / 2; @@ -78,7 +76,6 @@ void factor_vm::init_parameters_from_args(vm_parameters *p, int argc, vm_char ** { if(factor_arg(argv[i],STRING_LITERAL("-datastack=%d"),&p->ds_size)); else if(factor_arg(argv[i],STRING_LITERAL("-retainstack=%d"),&p->rs_size)); - else if(factor_arg(argv[i],STRING_LITERAL("-generations=%d"),&p->gen_count)); else if(factor_arg(argv[i],STRING_LITERAL("-young=%d"),&p->young_size)); else if(factor_arg(argv[i],STRING_LITERAL("-aging=%d"),&p->aging_size)); else if(factor_arg(argv[i],STRING_LITERAL("-tenured=%d"),&p->tenured_size)); diff --git a/vm/image.cpp b/vm/image.cpp index bf50b30d4b..1e10bd2886 100755 --- a/vm/image.cpp +++ b/vm/image.cpp @@ -21,8 +21,7 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p) if(good_size > p->tenured_size) p->tenured_size = good_size; - init_data_heap(p->gen_count, - p->young_size, + init_data_heap(p->young_size, p->aging_size, p->tenured_size, p->secure_gc); diff --git a/vm/image.hpp b/vm/image.hpp index a964d3eb13..5b1bcaf74a 100755 --- a/vm/image.hpp +++ b/vm/image.hpp @@ -32,7 +32,7 @@ struct vm_parameters { const vm_char *image_path; const vm_char *executable_path; cell ds_size, rs_size; - cell gen_count, young_size, aging_size, tenured_size; + cell young_size, aging_size, tenured_size; cell code_size; bool secure_gc; bool fep; diff --git a/vm/master.hpp b/vm/master.hpp index 0e34144099..2c4358f704 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -24,8 +24,9 @@ #include /* C++ headers */ -#include +#include #include +#include #if __GNUC__ == 4 #include diff --git a/vm/vm.hpp b/vm/vm.hpp index ce45a6122d..70283cdcea 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -157,7 +157,7 @@ struct factor_vm void reset_generation(cell i); void reset_generations(cell from, cell to); void set_data_heap(data_heap *data_); - void init_data_heap(cell gens,cell young_size,cell aging_size,cell tenured_size,bool secure_gc_); + void init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_); cell untagged_object_size(object *pointer); cell unaligned_object_size(object *pointer); void primitive_size(); @@ -231,7 +231,7 @@ struct factor_vm /* used during garbage collection only */ gc_state *current_gc; /* statistics */ - gc_stats stats[max_gen_count]; + gc_stats stats[gen_count]; u64 cards_scanned; u64 decks_scanned; u64 card_scan_time; @@ -255,11 +255,11 @@ struct factor_vm template void mark_object_code_block(object *object, Strategy &strategy); void free_unmarked_code_blocks(); void update_dirty_code_blocks(); - void begin_gc(cell requested_bytes); void collect_nursery(); void collect_aging(); - void collect_tenured(bool trace_contexts_); - void end_gc(); + void collect_aging_again(); + void collect_tenured(cell requested_bytes, bool trace_contexts_); + void record_gc_stats(); void garbage_collection(cell gen, bool growing_data_heap, bool trace_contexts, cell requested_bytes); void gc(); void primitive_gc(); From ed1ee19ce14ea472bad93e3039879092e524c7b4 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 04:36:34 -0500 Subject: [PATCH 09/63] vm: add a remembered set for code blocks which may reference young literals. Improves loading time --- vm/code_block.cpp | 11 ++---- vm/code_heap.cpp | 12 +++++++ vm/code_heap.hpp | 14 +++++--- vm/data_gc.cpp | 84 +++++++++++++++++++-------------------------- vm/data_gc.hpp | 3 -- vm/errors.cpp | 2 +- vm/inline_cache.cpp | 2 +- vm/layouts.hpp | 2 +- 8 files changed, 61 insertions(+), 69 deletions(-) diff --git a/vm/code_block.cpp b/vm/code_block.cpp index ec7da8af9f..e5dd57b05f 100755 --- a/vm/code_block.cpp +++ b/vm/code_block.cpp @@ -341,7 +341,7 @@ void factor_vm::update_word_references(code_block *compiled) the code heap with dead PICs that will be freed on the next GC, we add them to the free list immediately. */ else if(compiled->type == PIC_TYPE) - code->heap_free(compiled); + code->code_heap_free(compiled); else { word_references_updater updater(this); @@ -372,18 +372,12 @@ struct code_block_relocator { /* Perform all fixups on a code block */ void factor_vm::relocate_code_block(code_block *compiled) { - compiled->last_scan = data->nursery(); compiled->needs_fixup = false; code_block_relocator relocator(this); iterate_relocations(compiled,relocator); flush_icache_for(compiled); } -void relocate_code_block(code_block *compiled, factor_vm *myvm) -{ - return myvm->relocate_code_block(compiled); -} - /* Fixup labels. This is done at compile time, not image load time */ void factor_vm::fixup_labels(array *labels, code_block *compiled) { @@ -443,7 +437,6 @@ code_block *factor_vm::add_code_block(cell type, cell code_, cell labels_, cell /* compiled header */ compiled->type = type; - compiled->last_scan = data->nursery(); compiled->needs_fixup = true; /* slight space optimization */ @@ -466,7 +459,7 @@ code_block *factor_vm::add_code_block(cell type, cell code_, cell labels_, cell /* next time we do a minor GC, we have to scan the code heap for literals */ - this->code->last_code_heap_scan = data->nursery(); + this->code->write_barrier(compiled); return compiled; } diff --git a/vm/code_heap.cpp b/vm/code_heap.cpp index a0ad1a7dd0..305d8d1e60 100755 --- a/vm/code_heap.cpp +++ b/vm/code_heap.cpp @@ -5,6 +5,18 @@ namespace factor code_heap::code_heap(factor_vm *myvm, cell size) : heap(myvm,size) {} +void code_heap::write_barrier(code_block *compiled) +{ + remembered_set[compiled] = myvm->data->nursery(); + youngest_referenced_generation = myvm->data->nursery(); +} + +void code_heap::code_heap_free(code_block *compiled) +{ + remembered_set.erase(compiled); + heap_free(compiled); +} + /* Allocate a code heap during startup */ void factor_vm::init_code_heap(cell size) { diff --git a/vm/code_heap.hpp b/vm/code_heap.hpp index c0b6d9d1cf..0ccc4ee798 100755 --- a/vm/code_heap.hpp +++ b/vm/code_heap.hpp @@ -2,13 +2,17 @@ namespace factor { struct code_heap : heap { - /* What generation was being collected when trace_code_heap_roots() was last - called? Until the next call to add_code_block(), future - collections of younger generations don't have to touch the code - heap. */ - cell last_code_heap_scan; + /* Maps code blocks to the youngest generation containing + one of their literals. If this is tenured (0), the code block + is not part of the remembered set. */ + unordered_map remembered_set; + /* Minimum value in the above map. */ + cell youngest_referenced_generation; + explicit code_heap(factor_vm *myvm, cell size); + void write_barrier(code_block *compiled); + void code_heap_free(code_block *compiled); }; } diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 19a740ac70..748329bfc2 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -5,7 +5,7 @@ namespace factor void factor_vm::init_data_gc() { - code->last_code_heap_scan = data->nursery(); + code->youngest_referenced_generation = data->nursery(); } gc_state::gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_gen_) : @@ -287,47 +287,23 @@ template void factor_vm::trace_contexts(Strategy &strategy) /* Trace all literals referenced from a code block. Only for aging and nursery collections */ template void factor_vm::trace_literal_references(code_block *compiled, Strategy &strategy) { - if(current_gc->collecting_gen >= compiled->last_scan) - { - if(current_gc->collecting_accumulation_gen_p()) - compiled->last_scan = current_gc->collecting_gen; - else - compiled->last_scan = current_gc->collecting_gen + 1; - - trace_handle(&compiled->literals,strategy); - trace_handle(&compiled->relocation,strategy); - - /* once we finish tracing, re-visit this code block and update - literals */ - current_gc->dirty_code_blocks.insert(compiled); - } + trace_handle(&compiled->literals,strategy); + trace_handle(&compiled->relocation,strategy); } -template struct literal_reference_tracer { - factor_vm *myvm; - Strategy strategy; - - explicit literal_reference_tracer(factor_vm *myvm_, Strategy &strategy_) : - myvm(myvm_), strategy(strategy_) {} - - void operator()(code_block *compiled) - { - myvm->trace_literal_references(compiled,strategy); - } -}; - /* Trace literals referenced from all code blocks. Only for aging and nursery collections */ template void factor_vm::trace_code_heap_roots(Strategy &strategy) { - if(current_gc->collecting_gen >= code->last_code_heap_scan) + if(current_gc->collecting_gen >= code->youngest_referenced_generation) { - literal_reference_tracer tracer(this,strategy); - iterate_code_heap(tracer); + unordered_map::const_iterator iter = code->remembered_set.begin(); + unordered_map::const_iterator end = code->remembered_set.end(); - if(current_gc->collecting_accumulation_gen_p()) - code->last_code_heap_scan = current_gc->collecting_gen; - else - code->last_code_heap_scan = current_gc->collecting_gen + 1; + for(; iter != end; iter++) + { + if(current_gc->collecting_gen >= iter->second) + trace_literal_references(iter->first,strategy); + } code_heap_scans++; } @@ -340,9 +316,7 @@ template void factor_vm::mark_code_block(code_block *compiled check_code_address((cell)compiled); code->mark_block(compiled); - - trace_handle(&compiled->literals,strategy); - trace_handle(&compiled->relocation,strategy); + trace_literal_references(compiled,strategy); } struct literal_and_word_reference_updater { @@ -362,19 +336,34 @@ void factor_vm::free_unmarked_code_blocks() { literal_and_word_reference_updater updater(this); code->free_unmarked(updater); - code->last_code_heap_scan = current_gc->collecting_gen; + code->remembered_set.clear(); + code->youngest_referenced_generation = data->tenured(); } void factor_vm::update_dirty_code_blocks() { - std::set dirty_code_blocks = current_gc->dirty_code_blocks; - std::set::const_iterator iter = dirty_code_blocks.begin(); - std::set::const_iterator end = dirty_code_blocks.end(); + /* The youngest generation that any code block can now reference */ + cell gen; + + if(current_gc->collecting_accumulation_gen_p()) + gen = current_gc->collecting_gen; + else + gen = current_gc->collecting_gen + 1; + + unordered_map::iterator iter = code->remembered_set.begin(); + unordered_map::iterator end = code->remembered_set.end(); for(; iter != end; iter++) - update_literal_references(*iter); + { + if(current_gc->collecting_gen >= iter->second) + { + check_code_address((cell)iter->first); + update_literal_references(iter->first); + iter->second = gen; + } + } - dirty_code_blocks.clear(); + code->youngest_referenced_generation = gen; } template @@ -635,11 +624,8 @@ If growing_data_heap_ is true, we must grow the data heap to such a size that an allocation of requested_bytes won't fail */ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_, bool trace_contexts_, cell requested_bytes) { - if(gc_off) - { - critical_error("GC disabled",collecting_gen_); - return; - } + assert(!gc_off); + assert(!current_gc); current_gc = new gc_state(data,growing_data_heap_,collecting_gen_); diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index 80c7cd9a01..a5622ffd1e 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -25,9 +25,6 @@ struct gc_state { full, we go on to collect tenured */ bool collecting_aging_again; - /* A set of code blocks which need to have their literals updated */ - std::set dirty_code_blocks; - /* GC start time, for benchmarking */ u64 start_time; diff --git a/vm/errors.cpp b/vm/errors.cpp index 205733bf94..2435ac1c33 100755 --- a/vm/errors.cpp +++ b/vm/errors.cpp @@ -29,7 +29,7 @@ void factor_vm::throw_error(cell error, stack_frame *callstack_top) { /* If the error handler is set, we rewind any C stack frames and pass the error to user-space. */ - if(userenv[BREAK_ENV] != F) + if(!current_gc && userenv[BREAK_ENV] != F) { /* If error was thrown during heap scan, we re-enable the GC */ gc_off = false; diff --git a/vm/inline_cache.cpp b/vm/inline_cache.cpp index 1626af1965..1369714730 100755 --- a/vm/inline_cache.cpp +++ b/vm/inline_cache.cpp @@ -28,7 +28,7 @@ void factor_vm::deallocate_inline_cache(cell return_address) #endif if(old_type == PIC_TYPE) - code->heap_free(old_block); + code->code_heap_free(old_block); } /* Figure out what kind of type check the PIC needs based on the methods diff --git a/vm/layouts.hpp b/vm/layouts.hpp index 9357e927fb..0208fbd22e 100644 --- a/vm/layouts.hpp +++ b/vm/layouts.hpp @@ -207,7 +207,7 @@ struct heap_block { unsigned char status; /* free or allocated? */ unsigned char type; /* this is WORD_TYPE or QUOTATION_TYPE */ - unsigned char last_scan; /* the youngest generation in which this block's literals may live */ + unsigned char unused; unsigned char needs_fixup; /* is this a new block that needs full fixup? */ /* In bytes, includes this header */ From 2ca0044dd05a2a2c25c6d343bdd7427741c57071 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 04:57:44 -0500 Subject: [PATCH 10/63] vm: tweak --- vm/data_gc.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 748329bfc2..cf84fe0084 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -484,15 +484,18 @@ struct nursery_collector : copying_collector struct aging_collector : copying_collector { + zone *tenured; + explicit aging_collector(factor_vm *myvm_, zone *newspace_) : - copying_collector(myvm_,newspace_) {} + copying_collector(myvm_,newspace_), + tenured(&myvm->data->generations[myvm->data->tenured()]) {} bool should_copy_p(object *untagged) { if(newspace->contains_p(untagged)) return false; else - return !myvm->data->generations[myvm->data->tenured()].contains_p(untagged); + return !tenured->contains_p(untagged); } void copy_reachable_objects(cell scan, cell *end) From 16c325107249a897f462dafe9c701843c4eb0274 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 05:52:45 -0500 Subject: [PATCH 11/63] vm: free up a cell in compiled code block headers --- vm/callstack.cpp | 2 +- vm/code_block.cpp | 23 +++++------ vm/code_heap.cpp | 6 +++ vm/code_heap.hpp | 6 ++- vm/debug.cpp | 25 +++++------- vm/heap.cpp | 99 +++++++++++++++++---------------------------- vm/heap.hpp | 32 +++++++-------- vm/inline_cache.cpp | 2 +- vm/layouts.hpp | 45 +++++++++++++-------- vm/master.hpp | 4 ++ vm/quotations.cpp | 2 +- vm/vm.hpp | 6 +-- vm/words.cpp | 4 +- vm/words.hpp | 2 +- 14 files changed, 124 insertions(+), 134 deletions(-) diff --git a/vm/callstack.cpp b/vm/callstack.cpp index eccc4f9bfb..da3a2a0895 100755 --- a/vm/callstack.cpp +++ b/vm/callstack.cpp @@ -81,7 +81,7 @@ code_block *factor_vm::frame_code(stack_frame *frame) cell factor_vm::frame_type(stack_frame *frame) { - return frame_code(frame)->type; + return frame_code(frame)->type(); } cell factor_vm::frame_executing(stack_frame *frame) diff --git a/vm/code_block.cpp b/vm/code_block.cpp index e5dd57b05f..0967e01f4c 100755 --- a/vm/code_block.cpp +++ b/vm/code_block.cpp @@ -20,7 +20,7 @@ cell factor_vm::relocation_offset_of(relocation_entry r) void factor_vm::flush_icache_for(code_block *block) { - flush_icache((cell)block,block->size); + flush_icache((cell)block,block->size()); } int factor_vm::number_of_parameters(relocation_type type) @@ -290,7 +290,7 @@ struct literal_references_updater { /* Update pointers to literals from compiled code. */ void factor_vm::update_literal_references(code_block *compiled) { - if(!compiled->needs_fixup) + if(!code->needs_fixup_p(compiled)) { literal_references_updater updater(this); iterate_relocations(compiled,updater); @@ -331,7 +331,7 @@ to update references to other words, without worrying about literals or dlsyms. */ void factor_vm::update_word_references(code_block *compiled) { - if(compiled->needs_fixup) + if(code->needs_fixup_p(compiled)) relocate_code_block(compiled); /* update_word_references() is always applied to every block in the code heap. Since it resets all call sites to point to @@ -340,7 +340,7 @@ void factor_vm::update_word_references(code_block *compiled) are referenced after this is done. So instead of polluting the code heap with dead PICs that will be freed on the next GC, we add them to the free list immediately. */ - else if(compiled->type == PIC_TYPE) + else if(compiled->type() == PIC_TYPE) code->code_heap_free(compiled); else { @@ -372,7 +372,7 @@ struct code_block_relocator { /* Perform all fixups on a code block */ void factor_vm::relocate_code_block(code_block *compiled) { - compiled->needs_fixup = false; + code->needs_fixup.erase(compiled); code_block_relocator relocator(this); iterate_relocations(compiled,relocator); flush_icache_for(compiled); @@ -397,15 +397,15 @@ void factor_vm::fixup_labels(array *labels, code_block *compiled) } /* Might GC */ -code_block *factor_vm::allot_code_block(cell size) +code_block *factor_vm::allot_code_block(cell size, cell type) { - heap_block *block = code->heap_allot(size + sizeof(code_block)); + heap_block *block = code->heap_allot(size + sizeof(code_block),type); /* If allocation failed, do a code GC */ if(block == NULL) { gc(); - block = code->heap_allot(size + sizeof(code_block)); + block = code->heap_allot(size + sizeof(code_block),type); /* Insufficient room even after code GC, give up */ if(block == NULL) @@ -433,11 +433,7 @@ code_block *factor_vm::add_code_block(cell type, cell code_, cell labels_, cell gc_root literals(literals_,this); cell code_length = align8(array_capacity(code.untagged())); - code_block *compiled = allot_code_block(code_length); - - /* compiled header */ - compiled->type = type; - compiled->needs_fixup = true; + code_block *compiled = allot_code_block(code_length,type); /* slight space optimization */ if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0) @@ -460,6 +456,7 @@ code_block *factor_vm::add_code_block(cell type, cell code_, cell labels_, cell /* next time we do a minor GC, we have to scan the code heap for literals */ this->code->write_barrier(compiled); + this->code->needs_fixup.insert(compiled); return compiled; } diff --git a/vm/code_heap.cpp b/vm/code_heap.cpp index 305d8d1e60..d8fb6c53dd 100755 --- a/vm/code_heap.cpp +++ b/vm/code_heap.cpp @@ -11,9 +11,15 @@ void code_heap::write_barrier(code_block *compiled) youngest_referenced_generation = myvm->data->nursery(); } +bool code_heap::needs_fixup_p(code_block *compiled) +{ + return needs_fixup.count(compiled) > 0; +} + void code_heap::code_heap_free(code_block *compiled) { remembered_set.erase(compiled); + needs_fixup.erase(compiled); heap_free(compiled); } diff --git a/vm/code_heap.hpp b/vm/code_heap.hpp index 0ccc4ee798..1ac72e8218 100755 --- a/vm/code_heap.hpp +++ b/vm/code_heap.hpp @@ -2,16 +2,20 @@ namespace factor { struct code_heap : heap { + /* Set of blocks which need full relocation. */ + unordered_set needs_fixup; + /* Maps code blocks to the youngest generation containing one of their literals. If this is tenured (0), the code block is not part of the remembered set. */ unordered_map remembered_set; - + /* Minimum value in the above map. */ cell youngest_referenced_generation; explicit code_heap(factor_vm *myvm, cell size); void write_barrier(code_block *compiled); + bool needs_fixup_p(code_block *compiled); void code_heap_free(code_block *compiled); }; diff --git a/vm/debug.cpp b/vm/debug.cpp index 70d5b27766..e1c1fa5a85 100755 --- a/vm/debug.cpp +++ b/vm/debug.cpp @@ -308,28 +308,23 @@ void factor_vm::dump_code_heap() while(scan) { const char *status; - switch(scan->status) - { - case B_FREE: + if(scan->type() == FREE_BLOCK_TYPE) status = "free"; - break; - case B_ALLOCATED: - reloc_size += object_size(((code_block *)scan)->relocation); - literal_size += object_size(((code_block *)scan)->literals); - status = "allocated"; - break; - case B_MARKED: + else if(scan->marked_p()) + { reloc_size += object_size(((code_block *)scan)->relocation); literal_size += object_size(((code_block *)scan)->literals); status = "marked"; - break; - default: - status = "invalid"; - break; + } + else + { + reloc_size += object_size(((code_block *)scan)->relocation); + literal_size += object_size(((code_block *)scan)->literals); + status = "allocated"; } print_cell_hex((cell)scan); print_string(" "); - print_cell_hex(scan->size); print_string(" "); + print_cell_hex(scan->size()); print_string(" "); print_string(status); print_string("\n"); scan = code->next_block(scan); diff --git a/vm/heap.cpp b/vm/heap.cpp index 91ebc291cd..0f2f2fda1f 100644 --- a/vm/heap.cpp +++ b/vm/heap.cpp @@ -21,9 +21,9 @@ heap::heap(factor_vm *myvm_, cell size) 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) { - int index = block->size / block_size_increment; + int index = block->size() / block_size_increment; block->next_free = free.small_blocks[index]; free.small_blocks[index] = block; } @@ -52,17 +52,8 @@ void heap::build_free_list(cell size) /* Add all free blocks to the free list */ while(scan && scan < (heap_block *)end) { - switch(scan->status) - { - case B_FREE: + if(scan->type() == FREE_BLOCK_TYPE) add_to_free_list((free_heap_block *)scan); - break; - case B_ALLOCATED: - break; - default: - myvm->critical_error("Invalid scan->status",(cell)scan); - break; - } prev = scan; scan = next_block(scan); @@ -72,8 +63,9 @@ void heap::build_free_list(cell size) branch is only taken after loading a new image, not after code GC */ if((cell)(end + 1) <= seg->end) { - end->status = B_FREE; - end->size = seg->end - (cell)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); @@ -85,14 +77,14 @@ void heap::build_free_list(cell size) /* 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->size = seg->end - (cell)prev; + if(prev) prev->set_size(seg->end - (cell)prev); } } void heap::assert_free_block(free_heap_block *block) { - if(block->status != B_FREE) + if(block->type() != FREE_BLOCK_TYPE) myvm->critical_error("Invalid block in free list",(cell)block); } @@ -120,7 +112,7 @@ free_heap_block *heap::find_free_block(cell size) while(block) { assert_free_block(block); - if(block->size >= size) + if(block->size() >= size) { if(prev) prev->next_free = block->next_free; @@ -138,14 +130,14 @@ free_heap_block *heap::find_free_block(cell size) free_heap_block *heap::split_free_block(free_heap_block *block, cell size) { - if(block->size != size ) + if(block->size() != size ) { /* split the block in two */ free_heap_block *split = (free_heap_block *)((cell)block + size); - split->status = B_FREE; - split->size = block->size - size; + split->set_type(FREE_BLOCK_TYPE); + split->set_size(block->size() - size); split->next_free = block->next_free; - block->size = size; + block->set_size(size); add_to_free_list(split); } @@ -153,7 +145,7 @@ free_heap_block *heap::split_free_block(free_heap_block *block, cell size) } /* Allocate a block of memory from the mark and sweep GC heap */ -heap_block *heap::heap_allot(cell size) +heap_block *heap::heap_allot(cell size, cell type) { size = (size + block_size_increment - 1) & ~(block_size_increment - 1); @@ -161,8 +153,8 @@ heap_block *heap::heap_allot(cell size) if(block) { block = split_free_block(block,size); - - block->status = B_ALLOCATED; + block->set_type(type); + block->set_marked_p(false); return block; } else @@ -172,24 +164,13 @@ heap_block *heap::heap_allot(cell size) /* Deallocates a block manually */ void heap::heap_free(heap_block *block) { - block->status = B_FREE; + block->set_type(FREE_BLOCK_TYPE); add_to_free_list((free_heap_block *)block); } void heap::mark_block(heap_block *block) { - /* If already marked, do nothing */ - switch(block->status) - { - case B_MARKED: - return; - case B_ALLOCATED: - block->status = B_MARKED; - break; - default: - myvm->critical_error("Marking the wrong block",(cell)block); - break; - } + block->set_marked_p(true); } /* If in the middle of code GC, we have to grow the heap, data GC restarts from @@ -200,9 +181,7 @@ void heap::unmark_marked() while(scan) { - if(scan->status == B_MARKED) - scan->status = B_ALLOCATED; - + scan->set_marked_p(false); scan = next_block(scan); } } @@ -218,19 +197,16 @@ void heap::heap_usage(cell *used, cell *total_free, cell *max_free) while(scan) { - switch(scan->status) + cell size = scan->size(); + + if(scan->type() == FREE_BLOCK_TYPE) { - case B_ALLOCATED: - *used += scan->size; - break; - case B_FREE: - *total_free += scan->size; - if(scan->size > *max_free) - *max_free = scan->size; - break; - default: - myvm->critical_error("Invalid scan->status",(cell)scan); + *total_free += size; + if(size > *max_free) + *max_free = size; } + else + *used += size; scan = next_block(scan); } @@ -245,7 +221,7 @@ cell heap::heap_size() scan = next_block(scan); /* this is the last block in the heap, and it is free */ - if(scan->status == B_FREE) + if(scan->type() == FREE_BLOCK_TYPE) return (cell)scan - seg->start; /* otherwise the last block is allocated */ else @@ -260,14 +236,11 @@ cell heap::compute_heap_forwarding() while(scan) { - if(scan->status == B_ALLOCATED) + if(scan->type() != FREE_BLOCK_TYPE) { forwarding[scan] = address; - address += scan->size; + address += scan->size(); } - else if(scan->status == B_MARKED) - myvm->critical_error("Why is the block marked?",0); - scan = next_block(scan); } @@ -282,8 +255,8 @@ void heap::compact_heap() { heap_block *next = next_block(scan); - if(scan->status == B_ALLOCATED) - memmove(forwarding[scan],scan,scan->size); + if(scan->type() != FREE_BLOCK_TYPE) + memmove(forwarding[scan],scan,scan->size()); scan = next; } } @@ -291,16 +264,16 @@ void heap::compact_heap() heap_block *heap::free_allocated(heap_block *prev, heap_block *scan) { if(myvm->secure_gc) - memset(scan + 1,0,scan->size - sizeof(heap_block)); + memset(scan + 1,0,scan->size() - sizeof(heap_block)); - if(prev && prev->status == B_FREE) + if(prev && prev->type() == FREE_BLOCK_TYPE) { - prev->size += scan->size; + prev->set_size(prev->size() + scan->size()); return prev; } else { - scan->status = B_FREE; + scan->set_type(FREE_BLOCK_TYPE); return scan; } } diff --git a/vm/heap.hpp b/vm/heap.hpp index d878072057..07ed6bc291 100644 --- a/vm/heap.hpp +++ b/vm/heap.hpp @@ -19,7 +19,7 @@ struct heap { inline heap_block *next_block(heap_block *block) { - cell next = ((cell)block + block->size); + cell next = ((cell)block + block->size()); if(next == seg->end) return NULL; else @@ -43,7 +43,7 @@ struct heap { void assert_free_block(free_heap_block *block); free_heap_block *find_free_block(cell size); free_heap_block *split_free_block(free_heap_block *block, cell size); - heap_block *heap_allot(cell size); + heap_block *heap_allot(cell size, cell type); void heap_free(heap_block *block); void mark_block(heap_block *block); void unmark_marked(); @@ -65,30 +65,28 @@ struct heap { while(scan) { - switch(scan->status) + if(scan->type() == FREE_BLOCK_TYPE) { - case B_ALLOCATED: - prev = free_allocated(prev,scan); - break; - case B_FREE: - if(prev && prev->status == B_FREE) - prev->size += scan->size; + if(prev && prev->type() == FREE_BLOCK_TYPE) + prev->set_size(prev->size() + scan->size()); else prev = scan; - break; - case B_MARKED: - if(prev && prev->status == B_FREE) + } + else if(scan->marked_p()) + { + if(prev && prev->type() == FREE_BLOCK_TYPE) add_to_free_list((free_heap_block *)prev); - scan->status = B_ALLOCATED; + scan->set_marked_p(false); prev = scan; iter(scan); - break; } - + else + prev = free_allocated(prev,scan); + scan = next_block(scan); } - - if(prev && prev->status == B_FREE) + + if(prev && prev->type() == FREE_BLOCK_TYPE) add_to_free_list((free_heap_block *)prev); } }; diff --git a/vm/inline_cache.cpp b/vm/inline_cache.cpp index 1369714730..18d784a2c0 100755 --- a/vm/inline_cache.cpp +++ b/vm/inline_cache.cpp @@ -19,7 +19,7 @@ void factor_vm::deallocate_inline_cache(cell return_address) check_code_pointer((cell)old_xt); code_block *old_block = (code_block *)old_xt - 1; - cell old_type = old_block->type; + cell old_type = old_block->type(); #ifdef FACTOR_DEBUG /* The call target was either another PIC, diff --git a/vm/layouts.hpp b/vm/layouts.hpp index 0208fbd22e..eb08ff20f3 100644 --- a/vm/layouts.hpp +++ b/vm/layouts.hpp @@ -65,7 +65,8 @@ inline static cell align8(cell a) #define TYPE_COUNT 15 /* Not a real type, but code_block's type field can be set to this */ -#define PIC_TYPE 69 +#define PIC_TYPE 42 +#define FREE_BLOCK_TYPE 69 /* Constants used when floating-point trap exceptions are thrown */ enum @@ -196,34 +197,46 @@ struct string : public object { }; /* The compiled code heap is structured into blocks. */ -enum block_status -{ - B_FREE, - B_ALLOCATED, - B_MARKED -}; - struct heap_block { - unsigned char status; /* free or allocated? */ - unsigned char type; /* this is WORD_TYPE or QUOTATION_TYPE */ - unsigned char unused; - unsigned char needs_fixup; /* is this a new block that needs full fixup? */ + /* Bit 0: mark + Bit 1-7: type + Bit 8-...: size */ + cell header; - /* In bytes, includes this header */ - cell size; + bool marked_p() { return header & 1; } + void set_marked_p(bool marked) + { + if(marked) + header |= 1; + else + header &= ~1; + } + + cell type() { return (header >> 1) & 0x7f; } + void set_type(cell type) + { + header = ((header & ~(0x7f << 1)) | (type << 1)); + } + + cell size() { return (header >> 8); } + void set_size(cell size) + { + header = (header & 0xff) | (size << 8); + } }; struct free_heap_block : public heap_block { - free_heap_block *next_free; + free_heap_block *next_free; }; struct code_block : public heap_block { + cell unused; cell literals; /* # bytes */ cell relocation; /* tagged pointer to byte-array or f */ - + void *xt() { return (void *)(this + 1); } }; diff --git a/vm/master.hpp b/vm/master.hpp index 2c4358f704..457dbee0ab 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -30,17 +30,21 @@ #if __GNUC__ == 4 #include + #include namespace factor { using std::tr1::unordered_map; + using std::tr1::unordered_set; } #elif __GNUC__ == 3 #include + #include namespace factor { using boost::unordered_map; + using boost::unordered_set; } #else #error Factor requires GCC 3.x or later diff --git a/vm/quotations.cpp b/vm/quotations.cpp index a77b22844b..afb02bb485 100755 --- a/vm/quotations.cpp +++ b/vm/quotations.cpp @@ -281,7 +281,7 @@ void quotation_jit::iterate_quotation() void factor_vm::set_quot_xt(quotation *quot, code_block *code) { - if(code->type != QUOTATION_TYPE) + if(code->type() != QUOTATION_TYPE) critical_error("Bad param to set_quot_xt",(cell)code); quot->code = code; diff --git a/vm/vm.hpp b/vm/vm.hpp index 70283cdcea..5f327acb0b 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -513,8 +513,8 @@ struct factor_vm void check_code_address(cell address); void relocate_code_block(code_block *compiled); void fixup_labels(array *labels, code_block *compiled); - code_block *allot_code_block(cell size); - code_block *add_code_block(cell type,cell code_,cell labels_,cell relocation_,cell literals_); + code_block *allot_code_block(cell size, cell type); + code_block *add_code_block(cell type, cell code_, cell labels_, cell relocation_, cell literals_); inline bool stack_traces_p() { return userenv[STACK_TRACES_ENV] != F; @@ -548,7 +548,7 @@ struct factor_vm while(scan) { - if(scan->status != B_FREE) + if(scan->type() != FREE_BLOCK_TYPE) iter((code_block *)scan); scan = code->next_block(scan); } diff --git a/vm/words.cpp b/vm/words.cpp index 9d5ca80a01..72460a64b9 100644 --- a/vm/words.cpp +++ b/vm/words.cpp @@ -49,12 +49,12 @@ void factor_vm::primitive_word_xt() if(profiling_p) { dpush(allot_cell((cell)w->profiling->xt())); - dpush(allot_cell((cell)w->profiling + w->profiling->size)); + dpush(allot_cell((cell)w->profiling + w->profiling->size())); } else { dpush(allot_cell((cell)w->code->xt())); - dpush(allot_cell((cell)w->code + w->code->size)); + dpush(allot_cell((cell)w->code + w->code->size())); } } diff --git a/vm/words.hpp b/vm/words.hpp index 34cd48b640..1701def6dc 100644 --- a/vm/words.hpp +++ b/vm/words.hpp @@ -3,7 +3,7 @@ namespace factor inline bool word_optimized_p(word *word) { - return word->code->type == WORD_TYPE; + return word->code->type() == WORD_TYPE; } } From 697e2342d0255fa34680709dbab58c477a56e8af Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 06:25:07 -0500 Subject: [PATCH 12/63] vm: put code block owner directly in the header, instead of as the first entry in the literal table. Reduces x86-64 image size by ~700kb, also eliminates separate 'strip' set of staging images from deploy tool --- basis/command-line/command-line-docs.factor | 1 - basis/compiler/codegen/codegen.factor | 27 +++++++-------------- basis/compiler/codegen/fixup/fixup.factor | 17 ++++++++----- basis/tools/deploy/backend/backend.factor | 6 +---- basis/tools/deploy/deploy-tests.factor | 2 +- basis/tools/deploy/shaker/shaker.factor | 2 +- core/bootstrap/primitives.factor | 1 + vm/callstack.cpp | 11 +-------- vm/code_block.cpp | 9 ++++--- vm/code_heap.cpp | 25 ++++++++++++++++--- vm/data_gc.cpp | 1 + vm/factor.cpp | 6 ----- vm/image.cpp | 3 ++- vm/image.hpp | 1 - vm/jit.cpp | 5 ++-- vm/layouts.hpp | 4 +-- vm/primitives.cpp | 2 ++ vm/primitives.hpp | 1 + vm/run.hpp | 4 +-- vm/vm.hpp | 7 ++---- 20 files changed, 65 insertions(+), 70 deletions(-) diff --git a/basis/command-line/command-line-docs.factor b/basis/command-line/command-line-docs.factor index 6bcdd4f4af..697f95b14f 100644 --- a/basis/command-line/command-line-docs.factor +++ b/basis/command-line/command-line-docs.factor @@ -47,7 +47,6 @@ ARTICLE: "runtime-cli-args" "Command line switches for the VM" { { $snippet "-i=" { $emphasis "image" } } { "Specifies the image file to use; see " { $link "images" } } } { { $snippet "-datastack=" { $emphasis "n" } } "Data stack size, kilobytes" } { { $snippet "-retainstack=" { $emphasis "n" } } "Retain stack size, kilobytes" } - { { $snippet "-generations=" { $emphasis "n" } } "Number of generations, must equal 1, 2 or 3" } { { $snippet "-young=" { $emphasis "n" } } { "Size of youngest generation (0), megabytes" } } { { $snippet "-aging=" { $emphasis "n" } } "Size of aging generation (1), megabytes" } { { $snippet "-tenured=" { $emphasis "n" } } "Size of oldest generation (2), megabytes" } diff --git a/basis/compiler/codegen/codegen.factor b/basis/compiler/codegen/codegen.factor index 121f09a5a8..a750e6d610 100755 --- a/basis/compiler/codegen/codegen.factor +++ b/basis/compiler/codegen/codegen.factor @@ -32,30 +32,21 @@ SYMBOL: calls #! Compile this word later. calls get push ; -SYMBOL: compiling-word - -: compiled-stack-traces? ( -- ? ) 67 getenv ; - ! Mapping _label IDs to label instances SYMBOL: labels -: init-generator ( word -- ) +: init-generator ( -- ) H{ } clone labels set - V{ } clone calls set - compiling-word set - compiled-stack-traces? [ compiling-word get add-literal ] when ; + V{ } clone calls set ; : generate-insns ( asm -- code ) - [ - [ word>> init-generator ] - [ - instructions>> - [ - [ class insn-counts get inc-at ] - [ generate-insn ] - bi - ] each - ] bi + dup word>> [ + init-generator + instructions>> [ + [ class insn-counts get inc-at ] + [ generate-insn ] + bi + ] each ] with-fixup ; : generate ( mr -- asm ) diff --git a/basis/compiler/codegen/fixup/fixup.factor b/basis/compiler/codegen/fixup/fixup.factor index d44f6afd99..60dd055a5f 100755 --- a/basis/compiler/codegen/fixup/fixup.factor +++ b/basis/compiler/codegen/fixup/fixup.factor @@ -4,9 +4,12 @@ USING: 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 -accessors growable compiler.constants ; +accessors growable fry generalizations compiler.constants ; IN: compiler.codegen.fixup +! Owner +SYMBOL: compiling-word + ! Literal table SYMBOL: literal-table @@ -91,17 +94,19 @@ SYMBOL: relocation-table [ [ resolve-relative-label ] map concat ] bi* ; -: init-fixup ( -- ) +: init-fixup ( word -- ) + compiling-word set V{ } clone literal-table set V{ } clone label-table set BV{ } clone relocation-table set ; -: with-fixup ( quot -- code ) - [ +: with-fixup ( word quot -- code ) + '[ init-fixup - call + @ label-table [ resolve-labels ] change + compiling-word get literal-table get >array relocation-table get >byte-array label-table get - ] B{ } make 4array ; inline + ] B{ } make 5 narray ; inline diff --git a/basis/tools/deploy/backend/backend.factor b/basis/tools/deploy/backend/backend.factor index ba82276927..bd58c7505b 100755 --- a/basis/tools/deploy/backend/backend.factor +++ b/basis/tools/deploy/backend/backend.factor @@ -53,9 +53,7 @@ CONSTANT: theme-path "basis/ui/gadgets/theme/" ] { } make ; : staging-image-name ( profile -- name ) - "staging." - swap strip-word-names? [ "strip" suffix ] when - "-" join ".image" 3append temp-file ; + "-" join "staging." ".image" surround temp-file ; DEFER: ?make-staging-image @@ -72,7 +70,6 @@ DEFER: ?make-staging-image ] if "-output-image=" over staging-image-name append , "-include=" swap " " join append , - strip-word-names? [ "-no-stack-traces" , ] when "-no-user-init" , ] { } make ; @@ -102,7 +99,6 @@ DEFER: ?make-staging-image [ "-deploy-vocab=" prepend , ] [ make-deploy-config "-deploy-config=" prepend , ] bi "-output-image=" prepend , - strip-word-names? [ "-no-stack-traces" , ] when ] { } make ] bind ; diff --git a/basis/tools/deploy/deploy-tests.factor b/basis/tools/deploy/deploy-tests.factor index 012b540511..6a1f949b0b 100644 --- a/basis/tools/deploy/deploy-tests.factor +++ b/basis/tools/deploy/deploy-tests.factor @@ -11,7 +11,7 @@ IN: tools.deploy.tests [ t ] [ "hello-ui" shake-and-bake 1300000 small-enough? ] unit-test -[ "staging.math-threads-compiler-ui-strip.image" ] [ +[ "staging.math-threads-compiler-ui.image" ] [ "hello-ui" deploy-config [ bootstrap-profile staging-image-name file-name ] bind ] unit-test diff --git a/basis/tools/deploy/shaker/shaker.factor b/basis/tools/deploy/shaker/shaker.factor index c623ea4194..994073b149 100755 --- a/basis/tools/deploy/shaker/shaker.factor +++ b/basis/tools/deploy/shaker/shaker.factor @@ -208,7 +208,7 @@ IN: tools.deploy.shaker [ word? ] instances deploy-word-props? get [ 2dup strip-word-props ] unless deploy-word-defs? get [ dup strip-word-defs ] unless - strip-word-names? [ dup strip-word-names ] when + strip-word-names? [ dup strip-word-names strip-stack-traces ] when 2drop ; : compiler-classes ( -- seq ) diff --git a/core/bootstrap/primitives.factor b/core/bootstrap/primitives.factor index f42ab779f4..23da40d2c5 100644 --- a/core/bootstrap/primitives.factor +++ b/core/bootstrap/primitives.factor @@ -522,6 +522,7 @@ tuple { "optimized?" "words" (( word -- ? )) } { "quot-compiled?" "quotations" (( quot -- ? )) } { "vm-ptr" "vm" (( -- ptr )) } + { "strip-stack-traces" "kernel.private" (( -- )) } } [ [ first3 ] dip swap make-primitive ] each-index ! Bump build number diff --git a/vm/callstack.cpp b/vm/callstack.cpp index da3a2a0895..954eedcecb 100755 --- a/vm/callstack.cpp +++ b/vm/callstack.cpp @@ -86,16 +86,7 @@ cell factor_vm::frame_type(stack_frame *frame) cell factor_vm::frame_executing(stack_frame *frame) { - code_block *compiled = frame_code(frame); - if(compiled->literals == F || !stack_traces_p()) - return F; - else - { - array *literals = untag(compiled->literals); - cell executing = array_nth(literals,0); - check_data_pointer((object *)executing); - return executing; - } + return frame_code(frame)->owner; } stack_frame *factor_vm::frame_successor(stack_frame *frame) diff --git a/vm/code_block.cpp b/vm/code_block.cpp index 0967e01f4c..24c68c90ce 100755 --- a/vm/code_block.cpp +++ b/vm/code_block.cpp @@ -194,9 +194,9 @@ template void factor_vm::iterate_relocations(code_block *comp { byte_array *relocation = untag(compiled->relocation); - cell index = stack_traces_p() ? 1 : 0; - + cell index = 0; cell length = array_capacity(relocation) / sizeof(relocation_entry); + for(cell i = 0; i < length; i++) { relocation_entry rel = relocation->data()[i]; @@ -425,16 +425,19 @@ code_block *factor_vm::allot_code_block(cell size, cell type) } /* Might GC */ -code_block *factor_vm::add_code_block(cell type, cell code_, cell labels_, cell relocation_, cell literals_) +code_block *factor_vm::add_code_block(cell type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_) { gc_root code(code_,this); gc_root labels(labels_,this); + gc_root owner(owner_,this); gc_root relocation(relocation_,this); gc_root literals(literals_,this); cell code_length = align8(array_capacity(code.untagged())); code_block *compiled = allot_code_block(code_length,type); + compiled->owner = owner.value(); + /* slight space optimization */ if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0) compiled->relocation = F; diff --git a/vm/code_heap.cpp b/vm/code_heap.cpp index d8fb6c53dd..6cb952cd36 100755 --- a/vm/code_heap.cpp +++ b/vm/code_heap.cpp @@ -91,15 +91,17 @@ void factor_vm::primitive_modify_code_heap() case ARRAY_TYPE: { array *compiled_data = data.as().untagged(); - cell literals = array_nth(compiled_data,0); - cell relocation = array_nth(compiled_data,1); - cell labels = array_nth(compiled_data,2); - cell code = array_nth(compiled_data,3); + cell owner = array_nth(compiled_data,0); + cell literals = array_nth(compiled_data,1); + cell relocation = array_nth(compiled_data,2); + cell labels = array_nth(compiled_data,3); + cell code = array_nth(compiled_data,4); code_block *compiled = add_code_block( WORD_TYPE, code, labels, + owner, relocation, literals); @@ -245,4 +247,19 @@ void factor_vm::compact_code_heap() code->build_free_list(size); } +struct stack_trace_stripper { + explicit stack_trace_stripper() {} + + void operator()(code_block *compiled) + { + compiled->owner = F; + } +}; + +void factor_vm::primitive_strip_stack_traces() +{ + stack_trace_stripper stripper; + iterate_code_heap(stripper); +} + } diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index cf84fe0084..a5ce68d16e 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -287,6 +287,7 @@ template void factor_vm::trace_contexts(Strategy &strategy) /* Trace all literals referenced from a code block. Only for aging and nursery collections */ template void factor_vm::trace_literal_references(code_block *compiled, Strategy &strategy) { + trace_handle(&compiled->owner,strategy); trace_handle(&compiled->literals,strategy); trace_handle(&compiled->relocation,strategy); } diff --git a/vm/factor.cpp b/vm/factor.cpp index 9ade30318c..9a26cacf1a 100755 --- a/vm/factor.cpp +++ b/vm/factor.cpp @@ -49,8 +49,6 @@ void factor_vm::default_parameters(vm_parameters *p) p->console = false; #endif - - p->stack_traces = true; } bool factor_vm::factor_arg(const vm_char* str, const vm_char* arg, cell* value) @@ -85,7 +83,6 @@ void factor_vm::init_parameters_from_args(vm_parameters *p, int argc, vm_char ** else if(STRCMP(argv[i],STRING_LITERAL("-fep")) == 0) p->fep = true; else if(STRNCMP(argv[i],STRING_LITERAL("-i="),3) == 0) p->image_path = argv[i] + 3; else if(STRCMP(argv[i],STRING_LITERAL("-console")) == 0) p->console = true; - else if(STRCMP(argv[i],STRING_LITERAL("-no-stack-traces")) == 0) p->stack_traces = false; } } @@ -152,10 +149,7 @@ void factor_vm::init_factor(vm_parameters *p) gc_off = false; if(userenv[STAGE2_ENV] == F) - { - userenv[STACK_TRACES_ENV] = tag_boolean(p->stack_traces); do_stage1_init(); - } } /* May allocate memory */ diff --git a/vm/image.cpp b/vm/image.cpp index 1e10bd2886..90afaa82f2 100755 --- a/vm/image.cpp +++ b/vm/image.cpp @@ -295,8 +295,9 @@ void factor_vm::relocate_data() void factor_vm::fixup_code_block(code_block *compiled) { /* relocate literal table data */ - data_fixup(&compiled->relocation); + data_fixup(&compiled->owner); data_fixup(&compiled->literals); + data_fixup(&compiled->relocation); relocate_code_block(compiled); } diff --git a/vm/image.hpp b/vm/image.hpp index 5b1bcaf74a..80ee2556e9 100755 --- a/vm/image.hpp +++ b/vm/image.hpp @@ -37,7 +37,6 @@ struct vm_parameters { bool secure_gc; bool fep; bool console; - bool stack_traces; cell max_pic_size; }; diff --git a/vm/jit.cpp b/vm/jit.cpp index 3eb0f04547..77a311cb24 100644 --- a/vm/jit.cpp +++ b/vm/jit.cpp @@ -20,9 +20,7 @@ jit::jit(cell type_, cell owner_, factor_vm *vm) position(0), offset(0), parent_vm(vm) -{ - if(parent_vm->stack_traces_p()) literal(owner.value()); -} +{} void jit::emit_relocation(cell code_template_) { @@ -106,6 +104,7 @@ code_block *jit::to_code_block() type, code.elements.value(), F, /* no labels */ + owner.value(), relocation.elements.value(), literals.elements.value()); } diff --git a/vm/layouts.hpp b/vm/layouts.hpp index eb08ff20f3..68e2c7d87a 100644 --- a/vm/layouts.hpp +++ b/vm/layouts.hpp @@ -233,8 +233,8 @@ struct free_heap_block : public heap_block struct code_block : public heap_block { - cell unused; - cell literals; /* # bytes */ + cell owner; /* tagged pointer to word, quotation or f */ + cell literals; /* tagged pointer to array or f */ cell relocation; /* tagged pointer to byte-array or f */ void *xt() { return (void *)(this + 1); } diff --git a/vm/primitives.cpp b/vm/primitives.cpp index e2e663333f..9419518d79 100644 --- a/vm/primitives.cpp +++ b/vm/primitives.cpp @@ -164,6 +164,7 @@ const primitive_type primitives[] = { primitive_optimized_p, primitive_quot_compiled_p, primitive_vm_ptr, + primitive_strip_stack_traces, }; PRIMITIVE_FORWARD(bignum_to_fixnum) @@ -289,5 +290,6 @@ PRIMITIVE_FORWARD(inline_cache_stats) PRIMITIVE_FORWARD(optimized_p) PRIMITIVE_FORWARD(quot_compiled_p) PRIMITIVE_FORWARD(vm_ptr) +PRIMITIVE_FORWARD(strip_stack_traces) } diff --git a/vm/primitives.hpp b/vm/primitives.hpp index dd264869b2..cff22bf5fc 100644 --- a/vm/primitives.hpp +++ b/vm/primitives.hpp @@ -172,5 +172,6 @@ PRIMITIVE(inline_cache_stats); PRIMITIVE(optimized_p); PRIMITIVE(quot_compiled_p); PRIMITIVE(vm_ptr); +PRIMITIVE(strip_stack_traces); } diff --git a/vm/run.hpp b/vm/run.hpp index 23eabdfe14..cfc2acfb5c 100755 --- a/vm/run.hpp +++ b/vm/run.hpp @@ -87,8 +87,6 @@ enum special_object { THREADS_ENV = 64, RUN_QUEUE_ENV = 65, SLEEP_QUEUE_ENV = 66, - - STACK_TRACES_ENV = 67, }; #define FIRST_SAVE_ENV BOOT_ENV @@ -96,7 +94,7 @@ enum special_object { inline static bool save_env_p(cell i) { - return (i >= FIRST_SAVE_ENV && i <= LAST_SAVE_ENV) || i == STACK_TRACES_ENV; + return (i >= FIRST_SAVE_ENV && i <= LAST_SAVE_ENV); } } diff --git a/vm/vm.hpp b/vm/vm.hpp index 5f327acb0b..cb24ce8456 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -514,11 +514,7 @@ struct factor_vm void relocate_code_block(code_block *compiled); void fixup_labels(array *labels, code_block *compiled); code_block *allot_code_block(cell size, cell type); - code_block *add_code_block(cell type, cell code_, cell labels_, cell relocation_, cell literals_); - inline bool stack_traces_p() - { - return userenv[STACK_TRACES_ENV] != F; - } + code_block *add_code_block(cell type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_); //code_heap code_heap *code; @@ -540,6 +536,7 @@ struct factor_vm void forward_object_xts(); void fixup_object_xts(); void compact_code_heap(); + void primitive_strip_stack_traces(); /* Apply a function to every code block */ template void iterate_code_heap(Iterator &iter) From 8fcd6a3789cbfc8b4f3754655f1ebbd3904d29aa Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 06:36:43 -0500 Subject: [PATCH 13/63] vm: simplify logic --- vm/data_gc.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index a5ce68d16e..48c07e7c60 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -471,10 +471,7 @@ struct nursery_collector : copying_collector bool should_copy_p(object *untagged) { - if(newspace->contains_p(untagged)) - return false; - else - return myvm->nursery.contains_p(untagged); + return myvm->nursery.contains_p(untagged); } void copy_reachable_objects(cell scan, cell *end) From 231189191016ac88255e6d2f57b8aadf809b571f Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 06:47:56 -0500 Subject: [PATCH 14/63] vm: faster zone::contains_p() --- vm/data_heap.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/data_heap.hpp b/vm/data_heap.hpp index af7035b7d5..c4e8fe0d7b 100755 --- a/vm/data_heap.hpp +++ b/vm/data_heap.hpp @@ -20,7 +20,7 @@ struct zone { inline bool contains_p(object *pointer) { - return (cell)pointer >= start && (cell)pointer < end; + return ((cell)pointer - start) < size; } }; From 93d49428fb3d16d1c747dd4a3dd6543582810ed8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 08:55:42 -0500 Subject: [PATCH 15/63] vm: simplify some code --- vm/data_gc.cpp | 12 +++++++----- vm/data_heap.cpp | 50 ++++++++++++++++++++---------------------------- vm/vm.hpp | 9 ++++----- 3 files changed, 32 insertions(+), 39 deletions(-) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 48c07e7c60..89f3375c11 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -555,7 +555,7 @@ void factor_vm::collect_nursery() void factor_vm::collect_aging() { std::swap(data->generations[data->aging()],data->semispaces[data->aging()]); - reset_generations(data->aging(),data->aging()); + reset_generation(data->aging()); aging_collector collector(this,&data->generations[data->aging()]); @@ -566,7 +566,7 @@ void factor_vm::collect_aging() collector.go(); update_dirty_code_blocks(); - reset_generations(data->nursery(),data->nursery()); + nursery.here = nursery.start; } void factor_vm::collect_aging_again() @@ -580,7 +580,8 @@ void factor_vm::collect_aging_again() collector.go(); update_dirty_code_blocks(); - reset_generations(data->nursery(),data->aging()); + reset_generation(data->aging()); + nursery.here = nursery.start; } void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_) @@ -593,7 +594,7 @@ void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_) else { std::swap(data->generations[data->tenured()],data->semispaces[data->tenured()]); - reset_generations(data->tenured(),data->tenured()); + reset_generation(data->tenured()); } tenured_collector collector(this,&data->generations[data->tenured()]); @@ -603,7 +604,8 @@ void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_) collector.go(); free_unmarked_code_blocks(); - reset_generations(data->nursery(),data->aging()); + reset_generation(data->aging()); + nursery.here = nursery.start; if(current_gc->growing_data_heap) delete current_gc->old_data_heap; diff --git a/vm/data_heap.cpp b/vm/data_heap.cpp index d43d70e963..d5cfbb449d 100755 --- a/vm/data_heap.cpp +++ b/vm/data_heap.cpp @@ -76,60 +76,52 @@ data_heap::~data_heap() delete[] decks; } -void factor_vm::clear_cards(cell from, cell to) +void factor_vm::clear_cards(cell gen) { /* NOTE: reverse order due to heap layout. */ - card *first_card = addr_to_card(data->generations[to].start); - card *last_card = addr_to_card(data->generations[from].end); + card *first_card = addr_to_card(data->generations[gen].start); + card *last_card = addr_to_card(data->generations[gen].end); memset(first_card,0,last_card - first_card); } -void factor_vm::clear_decks(cell from, cell to) +void factor_vm::clear_decks(cell gen) { /* NOTE: reverse order due to heap layout. */ - card_deck *first_deck = addr_to_deck(data->generations[to].start); - card_deck *last_deck = addr_to_deck(data->generations[from].end); + card_deck *first_deck = addr_to_deck(data->generations[gen].start); + card_deck *last_deck = addr_to_deck(data->generations[gen].end); memset(first_deck,0,last_deck - first_deck); } -void factor_vm::clear_allot_markers(cell from, cell to) +void factor_vm::clear_allot_markers(cell gen) { - /* NOTE: reverse order due to heap layout. */ - card *first_card = addr_to_allot_marker((object *)data->generations[to].start); - card *last_card = addr_to_allot_marker((object *)data->generations[from].end); + card *first_card = addr_to_allot_marker((object *)data->generations[gen].start); + card *last_card = addr_to_allot_marker((object *)data->generations[gen].end); memset(first_card,invalid_allot_marker,last_card - first_card); } -void factor_vm::reset_generation(cell i) -{ - zone *z = (i == data->nursery() ? &nursery : &data->generations[i]); - - z->here = z->start; - if(secure_gc) - memset((void*)z->start,69,z->size); -} - /* After garbage collection, any generations which are now empty need to have their allocation pointers and cards reset. */ -void factor_vm::reset_generations(cell from, cell to) +void factor_vm::reset_generation(cell gen) { - cell i; - for(i = from; i <= to; i++) - reset_generation(i); + assert(gen != data->nursery()); - clear_cards(from,to); - clear_decks(from,to); - clear_allot_markers(from,to); + zone *z = &data->generations[gen]; + z->here = z->start; + if(secure_gc) memset((void*)z->start,69,z->size); + + clear_cards(gen); + clear_decks(gen); + clear_allot_markers(gen); } void factor_vm::set_data_heap(data_heap *data_) { data = data_; nursery = data->generations[data->nursery()]; + nursery.here = nursery.start; init_card_decks(); - clear_cards(data->nursery(),data->tenured()); - clear_decks(data->nursery(),data->tenured()); - clear_allot_markers(data->nursery(),data->tenured()); + reset_generation(data->aging()); + reset_generation(data->tenured()); } void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_) diff --git a/vm/vm.hpp b/vm/vm.hpp index cb24ce8456..d39163a209 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -151,11 +151,10 @@ struct factor_vm void init_card_decks(); data_heap *grow_data_heap(data_heap *data, cell requested_bytes); - void clear_cards(cell from, cell to); - void clear_decks(cell from, cell to); - void clear_allot_markers(cell from, cell to); - void reset_generation(cell i); - void reset_generations(cell from, cell to); + void clear_cards(cell gen); + void clear_decks(cell gen); + void clear_allot_markers(cell gen); + void reset_generation(cell gen); void set_data_heap(data_heap *data_); void init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_); cell untagged_object_size(object *pointer); From 6789a40fc6506e85237930dae9456da41f5ce6b7 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 19:15:54 -0500 Subject: [PATCH 16/63] vm: refactor forwarding pointer logic --- vm/data_gc.cpp | 112 +++++++++++++++++++++---------------------------- vm/data_gc.hpp | 4 +- vm/vm.hpp | 2 + 3 files changed, 51 insertions(+), 67 deletions(-) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 89f3375c11..8680ffa99a 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -17,16 +17,48 @@ gc_state::gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_ge gc_state::~gc_state() { } +template object *factor_vm::resolve_forwarding(object *untagged, Strategy &strategy) +{ + check_data_pointer(untagged); + + /* is there another forwarding pointer? */ + while(untagged->h.forwarding_pointer_p()) + untagged = untagged->h.forwarding_pointer(); + + /* we've found the destination */ + untagged->h.check_header(); + return untagged; +} + template void factor_vm::trace_handle(cell *handle, Strategy &strategy) { cell pointer = *handle; if(!immediate_p(pointer)) { - object *obj = untag(pointer); - check_data_pointer(obj); - if(strategy.should_copy_p(obj)) - *handle = strategy.copy_object(pointer); + object *untagged = untag(pointer); + if(strategy.should_copy_p(untagged)) + { + object *forwarding = resolve_forwarding(untagged,strategy); + if(forwarding == untagged) + *handle = strategy.copy_object(pointer); + else if(strategy.should_copy_p(forwarding)) + *handle = strategy.copy_object(RETAG(forwarding,TAG(pointer))); + else + *handle = RETAG(forwarding,TAG(pointer)); + } + } +} + +template void factor_vm::trace_slots(object *ptr, Strategy &strategy) +{ + cell *slot = (cell *)ptr; + cell *end = (cell *)((cell)ptr + binary_payload_start(ptr)); + + if(slot != end) + { + slot++; + for(; slot < end; slot++) trace_handle(slot,strategy); } } @@ -178,17 +210,13 @@ template void factor_vm::trace_registered_bignums(Strategy &s for(; iter < end; iter++) { - bignum **handle = (bignum **)(*iter); - bignum *pointer = *handle; + cell *handle = (cell *)(*iter); - if(pointer) + if(*handle) { - check_data_pointer(pointer); - if(strategy.should_copy_p(pointer)) - *handle = untag(strategy.copy_object(tag(pointer))); -#ifdef FACTOR_DEBUG - assert((*handle)->h.hi_tag() == BIGNUM_TYPE); -#endif + *handle |= BIGNUM_TYPE; + trace_handle(handle,strategy); + *handle &= ~BIGNUM_TYPE; } } } @@ -380,7 +408,7 @@ template Strategy ©ing_collector::strategy() } /* Given a pointer to oldspace, copy it to newspace */ -template object *copying_collector::copy_untagged_object_impl(object *pointer, cell size) +template object *copying_collector::copy_untagged_object(object *pointer, cell size) { if(newspace->here + size >= newspace->end) longjmp(current_gc->gc_unwind,1); @@ -395,47 +423,12 @@ template object *copying_collector::copy_untagged_o return newpointer; } -template object *copying_collector::copy_object_impl(object *untagged) -{ - object *newpointer = copy_untagged_object_impl(untagged,myvm->untagged_object_size(untagged)); - untagged->h.forward_to(newpointer); - return newpointer; -} - -/* Follow a chain of forwarding pointers */ -template object *copying_collector::resolve_forwarding(object *untagged) -{ - myvm->check_data_pointer(untagged); - - /* is there another forwarding pointer? */ - if(untagged->h.forwarding_pointer_p()) - return resolve_forwarding(untagged->h.forwarding_pointer()); - /* we've found the destination */ - else - { - untagged->h.check_header(); - if(should_copy_p(untagged)) - return copy_object_impl(untagged); - else - return untagged; - } -} - template cell copying_collector::copy_object(cell pointer) { object *untagged = myvm->untag(pointer); - - myvm->check_data_pointer(untagged); - - if(untagged->h.forwarding_pointer_p()) - untagged = resolve_forwarding(untagged->h.forwarding_pointer()); - else - { - untagged->h.check_header(); - untagged = copy_object_impl(untagged); - } - - return RETAG(untagged,TAG(pointer)); + object *newpointer = copy_untagged_object(untagged,myvm->untagged_object_size(untagged)); + untagged->h.forward_to(newpointer); + return RETAG(newpointer,TAG(pointer)); } template bool copying_collector::should_copy_p(object *pointer) @@ -445,18 +438,9 @@ template bool copying_collector::should_copy_p(obje template cell copying_collector::trace_next(cell scan) { - cell *obj = (cell *)scan; - cell *end = (cell *)(scan + myvm->binary_payload_start((object *)scan)); - - if(obj != end) - { - obj++; - - for(; obj < end; obj++) - myvm->trace_handle(obj,strategy()); - } - - return scan + myvm->untagged_object_size((object *)scan); + object *obj = (object *)scan; + myvm->trace_slots(obj,strategy()); + return scan + myvm->untagged_object_size(obj); } template void copying_collector::go() diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index a5622ffd1e..15332ad225 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -63,10 +63,8 @@ template struct copying_collector { explicit copying_collector(factor_vm *myvm_, zone *newspace); Strategy &strategy(); - object *copy_untagged_object_impl(object *pointer, cell size); + object *copy_untagged_object(object *pointer, cell size); cell trace_next(cell scan); - object *copy_object_impl(object *untagged); - object *resolve_forwarding(object *untagged); cell copy_object(cell pointer); bool should_copy_p(object *pointer); void go(); diff --git a/vm/vm.hpp b/vm/vm.hpp index d39163a209..06421f871d 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -237,7 +237,9 @@ struct factor_vm cell code_heap_scans; void init_data_gc(); + template object *resolve_forwarding(object *untagged, Strategy &strategy); template void trace_handle(cell *handle, Strategy &strategy); + template void trace_slots(object *ptr, Strategy &strategy); template void trace_card(card *ptr, cell gen, cell here, Strategy &strategy); template void trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy); template void trace_generation_cards(cell gen, Strategy &strategy); From 1f76a64e91d71379489e0bddf70ffc95a22ccfef Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 20:45:47 -0500 Subject: [PATCH 17/63] vm: more refactoring --- vm/data_gc.cpp | 50 +++++++++++++++++++++++++++++--------------------- vm/data_gc.hpp | 6 +++--- vm/vm.hpp | 1 + 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 8680ffa99a..1b12bddaf3 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -40,12 +40,15 @@ template void factor_vm::trace_handle(cell *handle, Strategy if(strategy.should_copy_p(untagged)) { object *forwarding = resolve_forwarding(untagged,strategy); + if(forwarding == untagged) - *handle = strategy.copy_object(pointer); + untagged = strategy.copy_object(untagged); else if(strategy.should_copy_p(forwarding)) - *handle = strategy.copy_object(RETAG(forwarding,TAG(pointer))); + untagged = strategy.copy_object(forwarding); else - *handle = RETAG(forwarding,TAG(pointer)); + untagged = forwarding; + + *handle = RETAG(untagged,TAG(pointer)); } } } @@ -62,6 +65,22 @@ template void factor_vm::trace_slots(object *ptr, Strategy &s } } +template object *factor_vm::promote_object(object *untagged, Strategy &strategy) +{ + cell size = untagged_object_size(untagged); + object *newpointer = strategy.allot(size); + if(!newpointer) longjmp(current_gc->gc_unwind,1); + + gc_stats *s = &stats[current_gc->collecting_gen]; + s->object_count++; + s->bytes_copied += size; + + memcpy(newpointer,untagged,size); + untagged->h.forward_to(newpointer); + + return newpointer; +} + template void factor_vm::trace_card(card *ptr, cell gen, cell here, Strategy &strategy) { cell card_scan = card_to_addr(ptr) + card_offset(ptr); @@ -407,28 +426,17 @@ template Strategy ©ing_collector::strategy() return static_cast(*this); } -/* Given a pointer to oldspace, copy it to newspace */ -template object *copying_collector::copy_untagged_object(object *pointer, cell size) +template object *copying_collector::allot(cell size) { - if(newspace->here + size >= newspace->end) - longjmp(current_gc->gc_unwind,1); - - object *newpointer = myvm->allot_zone(newspace,size); - - gc_stats *s = &myvm->stats[current_gc->collecting_gen]; - s->object_count++; - s->bytes_copied += size; - - memcpy(newpointer,pointer,size); - return newpointer; + if(newspace->here + size <= newspace->end) + return myvm->allot_zone(newspace,size); + else + return NULL; } -template cell copying_collector::copy_object(cell pointer) +template object *copying_collector::copy_object(object *untagged) { - object *untagged = myvm->untag(pointer); - object *newpointer = copy_untagged_object(untagged,myvm->untagged_object_size(untagged)); - untagged->h.forward_to(newpointer); - return RETAG(newpointer,TAG(pointer)); + return myvm->promote_object(untagged,strategy()); } template bool copying_collector::should_copy_p(object *pointer) diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index 15332ad225..c8b7b479c2 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -63,10 +63,10 @@ template struct copying_collector { explicit copying_collector(factor_vm *myvm_, zone *newspace); Strategy &strategy(); - object *copy_untagged_object(object *pointer, cell size); + object *allot(cell size); cell trace_next(cell scan); - cell copy_object(cell pointer); - bool should_copy_p(object *pointer); + object *copy_object(object *untagged); + bool should_copy_p(object *untagged); void go(); }; diff --git a/vm/vm.hpp b/vm/vm.hpp index 06421f871d..2ddb991b29 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -239,6 +239,7 @@ struct factor_vm void init_data_gc(); template object *resolve_forwarding(object *untagged, Strategy &strategy); template void trace_handle(cell *handle, Strategy &strategy); + template object *promote_object(object *pointer, Strategy &strategy); template void trace_slots(object *ptr, Strategy &strategy); template void trace_card(card *ptr, cell gen, cell here, Strategy &strategy); template void trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy); From 88afb451ba638ee976416e9d72cdd61f7c0ab5d9 Mon Sep 17 00:00:00 2001 From: Chris Double Date: Wed, 7 Oct 2009 15:54:18 +1300 Subject: [PATCH 18/63] Add S3 vocab --- extra/s3/authors.txt | 1 + extra/s3/s3.factor | 149 +++++++++++++++++++++++++++++++++++++++++++ extra/s3/summary.txt | 1 + extra/s3/tags.txt | 1 + 4 files changed, 152 insertions(+) create mode 100644 extra/s3/authors.txt create mode 100644 extra/s3/s3.factor create mode 100644 extra/s3/summary.txt create mode 100644 extra/s3/tags.txt diff --git a/extra/s3/authors.txt b/extra/s3/authors.txt new file mode 100644 index 0000000000..44b06f94bc --- /dev/null +++ b/extra/s3/authors.txt @@ -0,0 +1 @@ +Chris Double diff --git a/extra/s3/s3.factor b/extra/s3/s3.factor new file mode 100644 index 0000000000..24eae2cd89 --- /dev/null +++ b/extra/s3/s3.factor @@ -0,0 +1,149 @@ +! Copyright (C) 2009 Chris Double. All Rights Reserved. +! See http://factorcode.org/license.txt for BSD license. +USING: + accessors + assocs + base64 + calendar + calendar.format + checksums.hmac + checksums.sha + combinators + http + http.client + kernel + make + math.order + namespaces + sequences + sorting + strings + xml + xml.traversal +; +IN: s3 + +SYMBOL: key-id +SYMBOL: secret-key + +TUPLE: s3-request path mime-type date method headers bucket data ; + +: hashtable>headers ( hashtable -- seq ) + [ + [ swap % ":" % % "\n" % ] "" make + ] { } assoc>map [ <=> ] sort ; + +: signature ( s3-request -- string ) + [ + { + [ method>> % "\n" % "\n" % ] + [ mime-type>> % "\n" % ] + [ date>> timestamp>rfc822 % "\n" % ] + [ headers>> [ hashtable>headers [ % ] each ] when* ] + [ bucket>> [ "/" % % ] when* ] + [ path>> % ] + } cleave + ] "" make ; + +: sign ( s3-request -- string ) + [ + "AWS " % + key-id get % + ":" % + signature secret-key get sha1 hmac-bytes >base64 % + ] "" make ; + +: s3-url ( s3-request -- string ) + [ + "http://" % + dup bucket>> [ % "." % ] when* + "s3.amazonaws.com" % + path>> % + ] "" make ; + +: ( bucket path headers method -- request ) + s3-request new + swap >>method + swap >>headers + swap >>path + swap >>bucket + now >>date ; + +: sign-http-request ( s3-request http-request -- request ) + over date>> timestamp>rfc822 "Date" set-header + swap sign "Authorization" set-header ; + +: s3-get ( bucket path headers -- request data ) + "GET" dup s3-url + sign-http-request http-request ; + +: s3-put ( data bucket path headers -- request data ) + "PUT" dup s3-url swapd + sign-http-request http-request ; + +TUPLE: bucket name date ; + +: (buckets) ( xml -- seq ) + "Buckets" tag-named + "Bucket" tags-named [ + [ "Name" tag-named children>string ] + [ "CreationDate" tag-named children>string ] bi bucket boa + ] map ; + +: buckets ( -- seq ) + f "/" H{ } clone s3-get nip >string string>xml (buckets) ; + +: bucket-url ( bucket -- string ) + [ "http://" % % ".s3.amazonaws.com/" % ] "" make ; + +TUPLE: key name last-modified size ; + +: (keys) ( xml -- seq ) + "Contents" tags-named [ + [ "Key" tag-named children>string ] + [ "LastModified" tag-named children>string ] + [ "Size" tag-named children>string ] + tri key boa + ] map ; + +: keys ( bucket -- seq ) + "/" H{ } clone s3-get + nip >string string>xml (keys) ; + +: object-get ( bucket key -- response data ) + s3-request new + swap "/" prepend >>path + swap >>bucket + s3-url http-get ; + +: create-bucket ( bucket -- ) + "" swap "/" H{ } clone "PUT" + "application/octet-stream" >>mime-type + dup s3-url swapd + 0 "content-length" set-header + sign-http-request + http-request 2drop ; + +: delete-bucket ( bucket -- ) + "/" H{ } clone "DELETE" + dup s3-url sign-http-request http-request 2drop ; + +: put-object ( object type bucket key headers -- ) + [ "/" prepend ] dip "PUT" + over >>mime-type + [ swap >>data ] dip + dup s3-url swapd + dup header>> pick headers>> assoc-union >>header + sign-http-request + http-request 2drop ; + +! "testbucket" create-bucket +! "testbucket" delete-bucket +! buckets +! "testbucket" keys +! "hello world" binary encode "text/plain" "testbucket" "hello.txt" +! H{ { "x-amz-acl" "public-read" } } put-object +! "hello.txt" "text/plain" "testbucket" "hello.txt" +! H{ { "x-amz-acl" "public-read" } } put-object +! "testbucket" "hello.txt" object-get +! Need to write docs... diff --git a/extra/s3/summary.txt b/extra/s3/summary.txt new file mode 100644 index 0000000000..4b1a798144 --- /dev/null +++ b/extra/s3/summary.txt @@ -0,0 +1 @@ +Amazon S3 Wrapper diff --git a/extra/s3/tags.txt b/extra/s3/tags.txt new file mode 100644 index 0000000000..c0772185a0 --- /dev/null +++ b/extra/s3/tags.txt @@ -0,0 +1 @@ +web From e0408b9b10cde28bf1c201fbc0957a4012bc8ab4 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Wed, 7 Oct 2009 01:43:32 -0500 Subject: [PATCH 19/63] Adding bit fields to STRUCT: --- basis/classes/struct/struct-tests.factor | 5 ++ basis/classes/struct/struct.factor | 99 ++++++++++++++++++++++-- 2 files changed, 97 insertions(+), 7 deletions(-) diff --git a/basis/classes/struct/struct-tests.factor b/basis/classes/struct/struct-tests.factor index a026417171..b59fc4577c 100755 --- a/basis/classes/struct/struct-tests.factor +++ b/basis/classes/struct/struct-tests.factor @@ -352,3 +352,8 @@ STRUCT: struct-that's-a-word { x int } ; ] unit-test [ f ] [ "a-struct" c-types get key? ] unit-test + +STRUCT: bit-field-test + { a uint bits: 12 } + { b int bits: 2 } + { c char } ; diff --git a/basis/classes/struct/struct.factor b/basis/classes/struct/struct.factor index beddf07dd5..f8bdac530e 100755 --- a/basis/classes/struct/struct.factor +++ b/basis/classes/struct/struct.factor @@ -1,4 +1,4 @@ -! (c)Joe Groff bsd license +! (c)Joe Groff, Daniel Ehrenberg bsd license USING: accessors alien alien.c-types alien.data alien.parser arrays byte-arrays classes classes.parser classes.tuple classes.tuple.parser classes.tuple.private combinators combinators.short-circuit @@ -6,11 +6,29 @@ combinators.smart cpu.architecture definitions functors.backend fry generalizations generic.parser kernel kernel.private lexer libc locals macros make math math.order parser quotations sequences slots slots.private specialized-arrays vectors words -summary namespaces assocs vocabs.parser ; +summary namespaces assocs vocabs.parser math.functions bit-arrays ; +QUALIFIED: math IN: classes.struct SPECIALIZED-ARRAY: uchar + bits + +M: bits heap-size size>> 8 / ; + +M: bits c-type-align drop 1/8 ; + +: align ( m w -- n ) + ! Really, you could write 'align' correctly + ! for any real w; this is just a hack + ! that only works here + dup integer? [ [ ceiling ] dip math:align ] [ drop ] if ; + +PRIVATE> + ERROR: struct-must-have-slots ; M: struct-must-have-slots summary @@ -84,14 +102,56 @@ MACRO: ( class -- quot: ( ... -- struct ) ) : pad-struct-slots ( values class -- values' class ) [ struct-slots [ initial>> ] map over length tail append ] keep ; -: (reader-quot) ( slot -- quot ) +: read-normal ( slot -- quot ) [ type>> c-type-getter-boxer ] [ offset>> [ >c-ptr ] swap suffix ] bi prepend ; -: (writer-quot) ( slot -- quot ) +: bits@ ( slot -- beginning end ) + [ offset>> 8 * ] [ type>> size>> ] bi dupd + ; + +QUALIFIED: math.bits + +: bytes>bits ( byte-array -- bit-array ) + [ 8 math.bits: ] { } map-as ?{ } join ; + +: (read-bits) ( beginning end byte-array -- n ) + ! This is absurdly inefficient + bytes>bits subseq bit-array>integer ; + +: sign-extend ( n bits -- n' ) + ! formula from: + ! http://guru.multimedia.cx/fast-sign-extension/ + 1 - -1 swap shift [ + ] keep bitxor ; inline + +: read-bits ( slot -- quot ) + [ bits@ ] [ type>> signed?>> ] [ type>> size>> ] tri '[ + [ _ _ ] dip (underlying)>> (read-bits) + _ [ _ sign-extend ] when + ] ; + +: (reader-quot) ( slot -- quot ) + dup type>> bits? [ read-bits ] [ read-normal ] if ; + +: write-normal ( slot -- quot ) [ type>> c-setter ] [ offset>> [ >c-ptr ] swap suffix ] bi prepend ; +: overwrite ( donor victim -- ) + 0 swap copy ; + +: (write-bits) ( value offset end byte-array -- ) + ! This is absurdly inefficient + [ + [ [ swap - math.bits: ] 2keep ] [ bytes>bits ] bi* + replace-slice ?{ } like underlying>> + ] keep overwrite ; + +: write-bits ( slot -- quot ) + bits@ '[ [ _ _ ] dip (underlying)>> (write-bits) ] ; + +: (writer-quot) ( slot -- quot ) + dup type>> bits? [ write-bits ] [ write-normal ] if ; + : (boxer-quot) ( class -- quot ) '[ _ memory>struct ] ; @@ -196,10 +256,10 @@ M: struct-c-type c-struct? drop t ; ] reduce ; : union-struct-offsets ( slots -- size ) - [ 0 >>offset type>> heap-size ] [ max ] map-reduce ; + 1 [ 0 >>offset type>> heap-size max ] reduce ; : struct-align ( slots -- align ) - [ type>> c-type-align ] [ max ] map-reduce ; + 1 [ type>> c-type-align max ] reduce ; PRIVATE> M: struct byte-length class "struct-size" word-prop ; foldable @@ -273,11 +333,36 @@ ERROR: invalid-struct-slot token ; c-type c-type-boxed-class dup \ byte-array = [ drop \ c-ptr ] when ; +SYMBOL: bits: + +> { + { int [ t ] } + { uint [ f ] } + [ bad-type-for-bits ] + } case >>type ; + +: peel-off-struct-attributes ( slot-spec array -- slot-spec array ) + dup empty? [ + unclip { + { initial: [ [ first >>initial ] [ rest ] bi ] } + { read-only [ [ t >>read-only ] dip ] } + { bits: [ [ first set-bits ] [ rest ] bi ] } + [ bad-slot-attribute ] + } case + ] unless ; + +PRIVATE> + : ( name c-type attributes -- slot-spec ) [ struct-slot-spec new ] 3dip [ >>name ] [ [ >>type ] [ struct-slot-class >>class ] bi ] - [ [ dup empty? ] [ peel-off-attributes ] until drop ] tri* ; + [ [ dup empty? ] [ peel-off-struct-attributes ] until drop ] tri* ; Date: Wed, 7 Oct 2009 21:28:36 +0900 Subject: [PATCH 20/63] Euler 051 : added unit test, integration, author --- extra/project-euler/051/051-tests.factor | 4 ++++ extra/project-euler/051/authors.txt | 1 + extra/project-euler/project-euler.factor | 22 +++++++++++----------- 3 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 extra/project-euler/051/051-tests.factor create mode 100644 extra/project-euler/051/authors.txt diff --git a/extra/project-euler/051/051-tests.factor b/extra/project-euler/051/051-tests.factor new file mode 100644 index 0000000000..f6bd5bc37a --- /dev/null +++ b/extra/project-euler/051/051-tests.factor @@ -0,0 +1,4 @@ +USING: project-euler.051 tools.test ; +IN: project-euler.051.tests + +[ 121313 ] [ euler051 ] unit-test diff --git a/extra/project-euler/051/authors.txt b/extra/project-euler/051/authors.txt new file mode 100644 index 0000000000..790786959d --- /dev/null +++ b/extra/project-euler/051/authors.txt @@ -0,0 +1 @@ +Jon Harper \ No newline at end of file diff --git a/extra/project-euler/project-euler.factor b/extra/project-euler/project-euler.factor index 1bba3182d1..3438de8c2d 100644 --- a/extra/project-euler/project-euler.factor +++ b/extra/project-euler/project-euler.factor @@ -14,17 +14,17 @@ USING: definitions io io.files io.pathnames kernel math math.parser project-euler.037 project-euler.038 project-euler.039 project-euler.040 project-euler.041 project-euler.042 project-euler.043 project-euler.044 project-euler.045 project-euler.046 project-euler.047 project-euler.048 - project-euler.049 project-euler.052 project-euler.053 project-euler.054 - project-euler.055 project-euler.056 project-euler.057 project-euler.058 - project-euler.059 project-euler.063 project-euler.067 project-euler.069 - project-euler.071 project-euler.072 project-euler.073 project-euler.074 - project-euler.075 project-euler.076 project-euler.079 project-euler.085 - project-euler.092 project-euler.097 project-euler.099 project-euler.100 - project-euler.102 project-euler.112 project-euler.116 project-euler.117 - project-euler.124 project-euler.134 project-euler.148 project-euler.150 - project-euler.151 project-euler.164 project-euler.169 project-euler.173 - project-euler.175 project-euler.186 project-euler.190 project-euler.203 - project-euler.215 ; + project-euler.049 project-euler.051 project-euler.052 project-euler.053 + project-euler.054 project-euler.055 project-euler.056 project-euler.057 + project-euler.058 project-euler.059 project-euler.063 project-euler.067 + project-euler.069 project-euler.071 project-euler.072 project-euler.073 + project-euler.074 project-euler.075 project-euler.076 project-euler.079 + project-euler.085 project-euler.092 project-euler.097 project-euler.099 + project-euler.100 project-euler.102 project-euler.112 project-euler.116 + project-euler.117 project-euler.124 project-euler.134 project-euler.148 + project-euler.150 project-euler.151 project-euler.164 project-euler.169 + project-euler.173 project-euler.175 project-euler.186 project-euler.190 + project-euler.203 project-euler.215 ; IN: project-euler Date: Wed, 7 Oct 2009 08:33:54 -0500 Subject: [PATCH 21/63] vm: more code cleanups --- vm/code_heap.cpp | 10 ++-- vm/code_heap.hpp | 2 +- vm/contexts.cpp | 4 +- vm/data_gc.cpp | 96 +++++++++++++----------------- vm/data_gc.hpp | 16 +++-- vm/data_heap.cpp | 30 +++++----- vm/data_heap.hpp | 23 +++---- vm/errors.cpp | 20 +++---- vm/errors.hpp | 4 +- vm/heap.cpp | 9 ++- vm/heap.hpp | 4 +- vm/image.cpp | 8 +-- vm/os-unix.cpp | 6 +- vm/os-windows.cpp | 5 +- vm/segments.hpp | 3 +- vm/vm.hpp | 148 ++++++++++++++++++++++++++-------------------- 16 files changed, 201 insertions(+), 187 deletions(-) diff --git a/vm/code_heap.cpp b/vm/code_heap.cpp index 6cb952cd36..f07639d9bb 100755 --- a/vm/code_heap.cpp +++ b/vm/code_heap.cpp @@ -3,12 +3,12 @@ namespace factor { -code_heap::code_heap(factor_vm *myvm, cell size) : heap(myvm,size) {} +code_heap::code_heap(bool secure_gc, cell size) : heap(secure_gc,size) {} void code_heap::write_barrier(code_block *compiled) { - remembered_set[compiled] = myvm->data->nursery(); - youngest_referenced_generation = myvm->data->nursery(); + remembered_set[compiled] = nursery_gen; + youngest_referenced_generation = nursery_gen; } bool code_heap::needs_fixup_p(code_block *compiled) @@ -26,7 +26,7 @@ void code_heap::code_heap_free(code_block *compiled) /* Allocate a code heap during startup */ void factor_vm::init_code_heap(cell size) { - code = new code_heap(this,size); + code = new code_heap(secure_gc,size); } bool factor_vm::in_code_heap_p(cell ptr) @@ -228,7 +228,7 @@ critical here */ void factor_vm::compact_code_heap() { /* Free all unreachable code blocks, don't trace contexts */ - garbage_collection(data->tenured(),false,false,0); + garbage_collection(tenured_gen,false,false,0); /* Figure out where the code heap blocks are going to end up */ cell size = code->compute_heap_forwarding(); diff --git a/vm/code_heap.hpp b/vm/code_heap.hpp index 1ac72e8218..feea7da307 100755 --- a/vm/code_heap.hpp +++ b/vm/code_heap.hpp @@ -13,7 +13,7 @@ struct code_heap : heap { /* Minimum value in the above map. */ cell youngest_referenced_generation; - explicit code_heap(factor_vm *myvm, cell size); + explicit code_heap(bool secure_gc, cell size); void write_barrier(code_block *compiled); bool needs_fixup_p(code_block *compiled); void code_heap_free(code_block *compiled); diff --git a/vm/contexts.cpp b/vm/contexts.cpp index 2b7a55d491..78dc2ccd3f 100644 --- a/vm/contexts.cpp +++ b/vm/contexts.cpp @@ -44,8 +44,8 @@ context *factor_vm::alloc_context() else { new_context = new context; - new_context->datastack_region = new segment(this,ds_size); - new_context->retainstack_region = new segment(this,rs_size); + new_context->datastack_region = new segment(ds_size); + new_context->retainstack_region = new segment(rs_size); } return new_context; diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 1b12bddaf3..0fa5e1b07f 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -5,7 +5,7 @@ namespace factor void factor_vm::init_data_gc() { - code->youngest_referenced_generation = data->nursery(); + code->youngest_referenced_generation = nursery_gen; } gc_state::gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_gen_) : @@ -71,7 +71,7 @@ template object *factor_vm::promote_object(object *untagged, object *newpointer = strategy.allot(size); if(!newpointer) longjmp(current_gc->gc_unwind,1); - gc_stats *s = &stats[current_gc->collecting_gen]; + generation_stats *s = &stats.generations[current_gc->collecting_gen]; s->object_count++; s->bytes_copied += size; @@ -91,7 +91,7 @@ template void factor_vm::trace_card(card *ptr, cell gen, cell strategy.copy_reachable_objects(card_scan,&card_end); - cards_scanned++; + stats.cards_scanned++; } template void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy) @@ -122,7 +122,7 @@ template void factor_vm::trace_card_deck(card_deck *deck, cel } } - decks_scanned++; + stats.decks_scanned++; } /* Trace all objects referenced from marked cards */ @@ -142,11 +142,11 @@ template void factor_vm::trace_generation_cards(cell gen, Str /* after the collection, no old->nursery pointers remain anywhere, but old->aging pointers might remain in tenured space */ - if(gen == data->tenured()) + if(gen == tenured_gen) unmask = card_points_to_nursery; /* after the collection, all cards in aging space can be cleared */ - else if(gen == data->aging()) + else if(gen == aging_gen) unmask = card_mark_mask; else { @@ -201,7 +201,7 @@ template void factor_vm::trace_cards(Strategy &strategy) for(i = current_gc->collecting_gen + 1; i < gen_count; i++) trace_generation_cards(i,strategy); - card_scan_time += (current_micros() - start); + stats.card_scan_time += (current_micros() - start); } /* Copy all tagged pointers in a range of memory */ @@ -353,7 +353,7 @@ template void factor_vm::trace_code_heap_roots(Strategy &stra trace_literal_references(iter->first,strategy); } - code_heap_scans++; + stats.code_heap_scans++; } } @@ -385,7 +385,7 @@ void factor_vm::free_unmarked_code_blocks() literal_and_word_reference_updater updater(this); code->free_unmarked(updater); code->remembered_set.clear(); - code->youngest_referenced_generation = data->tenured(); + code->youngest_referenced_generation = tenured_gen; } void factor_vm::update_dirty_code_blocks() @@ -429,7 +429,11 @@ template Strategy ©ing_collector::strategy() template object *copying_collector::allot(cell size) { if(newspace->here + size <= newspace->end) - return myvm->allot_zone(newspace,size); + { + object *obj = newspace->allot(size); + myvm->allot_barrier(obj); + return obj; + } else return NULL; } @@ -478,7 +482,7 @@ struct aging_collector : copying_collector explicit aging_collector(factor_vm *myvm_, zone *newspace_) : copying_collector(myvm_,newspace_), - tenured(&myvm->data->generations[myvm->data->tenured()]) {} + tenured(&myvm->data->generations[tenured_gen]) {} bool should_copy_p(object *untagged) { @@ -532,7 +536,7 @@ struct tenured_collector : copying_collector void factor_vm::collect_nursery() { - nursery_collector collector(this,&data->generations[data->aging()]); + nursery_collector collector(this,&data->generations[aging_gen]); trace_roots(collector); trace_contexts(collector); @@ -546,10 +550,10 @@ void factor_vm::collect_nursery() void factor_vm::collect_aging() { - std::swap(data->generations[data->aging()],data->semispaces[data->aging()]); - reset_generation(data->aging()); + std::swap(data->generations[aging_gen],data->semispaces[aging_gen]); + reset_generation(aging_gen); - aging_collector collector(this,&data->generations[data->aging()]); + aging_collector collector(this,&data->generations[aging_gen]); trace_roots(collector); trace_contexts(collector); @@ -563,7 +567,7 @@ void factor_vm::collect_aging() void factor_vm::collect_aging_again() { - aging_again_collector collector(this,&data->generations[data->tenured()]); + aging_again_collector collector(this,&data->generations[tenured_gen]); trace_roots(collector); trace_contexts(collector); @@ -572,7 +576,7 @@ void factor_vm::collect_aging_again() collector.go(); update_dirty_code_blocks(); - reset_generation(data->aging()); + reset_generation(aging_gen); nursery.here = nursery.start; } @@ -585,18 +589,18 @@ void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_) } else { - std::swap(data->generations[data->tenured()],data->semispaces[data->tenured()]); - reset_generation(data->tenured()); + std::swap(data->generations[tenured_gen],data->semispaces[tenured_gen]); + reset_generation(tenured_gen); } - tenured_collector collector(this,&data->generations[data->tenured()]); + tenured_collector collector(this,&data->generations[tenured_gen]); trace_roots(collector); if(trace_contexts_) trace_contexts(collector); collector.go(); free_unmarked_code_blocks(); - reset_generation(data->aging()); + reset_generation(aging_gen); nursery.here = nursery.start; if(current_gc->growing_data_heap) @@ -605,7 +609,7 @@ void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_) void factor_vm::record_gc_stats() { - gc_stats *s = &stats[current_gc->collecting_gen]; + generation_stats *s = &stats.generations[current_gc->collecting_gen]; cell gc_elapsed = (current_micros() - current_gc->start_time); s->collections++; @@ -673,7 +677,7 @@ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_ void factor_vm::gc() { - garbage_collection(data->tenured(),false,true,0); + garbage_collection(tenured_gen,false,true,0); } void factor_vm::primitive_gc() @@ -690,7 +694,7 @@ void factor_vm::primitive_gc_stats() for(i = 0; i < gen_count; i++) { - gc_stats *s = &stats[i]; + generation_stats *s = &stats.generations[i]; result.add(allot_cell(s->collections)); result.add(tag(long_long_to_bignum(s->gc_time))); result.add(tag(long_long_to_bignum(s->max_gc_time))); @@ -702,10 +706,10 @@ void factor_vm::primitive_gc_stats() } result.add(tag(ulong_long_to_bignum(total_gc_time))); - result.add(tag(ulong_long_to_bignum(cards_scanned))); - result.add(tag(ulong_long_to_bignum(decks_scanned))); - result.add(tag(ulong_long_to_bignum(card_scan_time))); - result.add(allot_cell(code_heap_scans)); + result.add(tag(ulong_long_to_bignum(stats.cards_scanned))); + result.add(tag(ulong_long_to_bignum(stats.decks_scanned))); + result.add(tag(ulong_long_to_bignum(stats.card_scan_time))); + result.add(allot_cell(stats.code_heap_scans)); result.trim(); dpush(result.elements.value()); @@ -713,13 +717,7 @@ void factor_vm::primitive_gc_stats() void factor_vm::clear_gc_stats() { - for(cell i = 0; i < gen_count; i++) - memset(&stats[i],0,sizeof(gc_stats)); - - cards_scanned = 0; - decks_scanned = 0; - card_scan_time = 0; - code_heap_scans = 0; + memset(&stats,0,sizeof(gc_stats)); } void factor_vm::primitive_clear_gc_stats() @@ -763,7 +761,7 @@ void factor_vm::inline_gc(cell *gc_roots_base, cell gc_roots_size) for(cell i = 0; i < gc_roots_size; i++) gc_locals.push_back((cell)&gc_roots_base[i]); - garbage_collection(data->nursery(),false,true,0); + garbage_collection(nursery_gen,false,true,0); for(cell i = 0; i < gc_roots_size; i++) gc_locals.pop_back(); @@ -775,15 +773,6 @@ VM_C_API void inline_gc(cell *gc_roots_base, cell gc_roots_size, factor_vm *myvm VM_PTR->inline_gc(gc_roots_base,gc_roots_size); } -inline object *factor_vm::allot_zone(zone *z, cell a) -{ - cell h = z->here; - z->here = h + align8(a); - object *obj = (object *)h; - allot_barrier(obj); - return obj; -} - /* * It is up to the caller to fill in the object's fields in a meaningful * fashion! @@ -801,33 +790,32 @@ object *factor_vm::allot_object(header header, cell size) { /* If there is insufficient room, collect the nursery */ if(nursery.here + size > nursery.end) - garbage_collection(data->nursery(),false,true,0); + garbage_collection(nursery_gen,false,true,0); - cell h = nursery.here; - nursery.here = h + align8(size); - obj = (object *)h; + obj = nursery.allot(size); } /* If the object is bigger than the nursery, allocate it in tenured space */ else { - zone *tenured = &data->generations[data->tenured()]; + zone *tenured = &data->generations[tenured_gen]; /* If tenured space does not have enough room, collect */ if(tenured->here + size > tenured->end) { gc(); - tenured = &data->generations[data->tenured()]; + tenured = &data->generations[tenured_gen]; } /* If it still won't fit, grow the heap */ if(tenured->here + size > tenured->end) { - garbage_collection(data->tenured(),true,true,size); - tenured = &data->generations[data->tenured()]; + garbage_collection(tenured_gen,true,true,size); + tenured = &data->generations[tenured_gen]; } - obj = allot_zone(tenured,size); + obj = tenured->allot(size); + allot_barrier(obj); /* Allows initialization code to store old->new pointers without hitting the write barrier in the common case of diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index c8b7b479c2..04a9682ae5 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -2,7 +2,7 @@ namespace factor { /* statistics */ -struct gc_stats { +struct generation_stats { cell collections; u64 gc_time; u64 max_gc_time; @@ -10,6 +10,14 @@ struct gc_stats { u64 bytes_copied; }; +struct gc_stats { + generation_stats generations[gen_count]; + u64 cards_scanned; + u64 decks_scanned; + u64 card_scan_time; + cell code_heap_scans; +}; + struct gc_state { /* The data heap we're collecting */ data_heap *data; @@ -35,17 +43,17 @@ struct gc_state { inline bool collecting_nursery_p() { - return collecting_gen == data->nursery(); + return collecting_gen == nursery_gen; } inline bool collecting_aging_p() { - return collecting_gen == data->aging(); + return collecting_gen == aging_gen; } inline bool collecting_tenured_p() { - return collecting_gen == data->tenured(); + return collecting_gen == tenured_gen; } inline bool collecting_accumulation_gen_p() diff --git a/vm/data_heap.cpp b/vm/data_heap.cpp index d5cfbb449d..5ccde31f37 100755 --- a/vm/data_heap.cpp +++ b/vm/data_heap.cpp @@ -25,7 +25,7 @@ data_heap::data_heap(factor_vm *myvm, cell young_size_, cell aging_size_, cell t total_size += deck_size; - seg = new segment(myvm,total_size); + seg = new segment(total_size); generations = new zone[gen_count]; semispaces = new zone[gen_count]; @@ -43,17 +43,17 @@ data_heap::data_heap(factor_vm *myvm, cell young_size_, cell aging_size_, cell t cell alloter = align(seg->start,deck_size); - alloter = generations[tenured()].init_zone(tenured_size,alloter); - alloter = semispaces[tenured()].init_zone(tenured_size,alloter); + alloter = generations[tenured_gen].init_zone(tenured_size,alloter); + alloter = semispaces[tenured_gen].init_zone(tenured_size,alloter); - alloter = generations[aging()].init_zone(aging_size,alloter); - alloter = semispaces[aging()].init_zone(aging_size,alloter); + alloter = generations[aging_gen].init_zone(aging_size,alloter); + alloter = semispaces[aging_gen].init_zone(aging_size,alloter); - alloter = generations[nursery()].init_zone(young_size,alloter); - alloter = semispaces[nursery()].init_zone(0,alloter); + alloter = generations[nursery_gen].init_zone(young_size,alloter); + alloter = semispaces[nursery_gen].init_zone(0,alloter); if(seg->end - alloter > deck_size) - myvm->critical_error("Bug in alloc_data_heap",alloter); + critical_error("Bug in alloc_data_heap",alloter); } data_heap *factor_vm::grow_data_heap(data_heap *data, cell requested_bytes) @@ -103,7 +103,7 @@ void factor_vm::clear_allot_markers(cell gen) their allocation pointers and cards reset. */ void factor_vm::reset_generation(cell gen) { - assert(gen != data->nursery()); + assert(gen != nursery_gen); zone *z = &data->generations[gen]; z->here = z->start; @@ -117,11 +117,11 @@ void factor_vm::reset_generation(cell gen) void factor_vm::set_data_heap(data_heap *data_) { data = data_; - nursery = data->generations[data->nursery()]; + nursery = data->generations[nursery_gen]; nursery.here = nursery.start; init_card_decks(); - reset_generation(data->aging()); - reset_generation(data->tenured()); + reset_generation(aging_gen); + reset_generation(tenured_gen); } void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_) @@ -234,7 +234,7 @@ void factor_vm::primitive_data_room() cell gen; for(gen = 0; gen < gen_count; gen++) { - zone *z = (gen == data->nursery() ? &nursery : &data->generations[gen]); + zone *z = (gen == nursery_gen ? &nursery : &data->generations[gen]); a.add(tag_fixnum((z->end - z->here) >> 10)); a.add(tag_fixnum((z->size) >> 10)); } @@ -246,7 +246,7 @@ void factor_vm::primitive_data_room() /* Disables GC and activates next-object ( -- obj ) primitive */ void factor_vm::begin_scan() { - heap_scan_ptr = data->generations[data->tenured()].start; + heap_scan_ptr = data->generations[tenured_gen].start; gc_off = true; } @@ -265,7 +265,7 @@ cell factor_vm::next_object() if(!gc_off) general_error(ERROR_HEAP_SCAN,F,F,NULL); - if(heap_scan_ptr >= data->generations[data->tenured()].here) + if(heap_scan_ptr >= data->generations[tenured_gen].here) return F; object *obj = (object *)heap_scan_ptr; diff --git a/vm/data_heap.hpp b/vm/data_heap.hpp index c4e8fe0d7b..cd53d66768 100755 --- a/vm/data_heap.hpp +++ b/vm/data_heap.hpp @@ -9,7 +9,7 @@ struct zone { cell here; cell size; cell end; - + cell init_zone(cell size_, cell start_) { size = size_; @@ -17,11 +17,18 @@ struct zone { end = start_ + size_; return end; } - + inline bool contains_p(object *pointer) { return ((cell)pointer - start) < size; } + + inline object *allot(cell size) + { + cell h = here; + here = h + align8(size); + return (object *)h; + } }; struct data_heap { @@ -43,19 +50,13 @@ struct data_heap { char *decks; char *decks_end; - /* the 0th generation is where new objects are allocated. */ - cell nursery() { return 0; } - - /* where objects hang around */ - cell aging() { return 1; } - - /* the oldest generation */ - cell tenured() { return 2; } - explicit data_heap(factor_vm *myvm, cell young_size, cell aging_size, cell tenured_size); ~data_heap(); }; +static const cell nursery_gen = 0; +static const cell aging_gen = 1; +static const cell tenured_gen = 2; static const cell gen_count = 3; } diff --git a/vm/errors.cpp b/vm/errors.cpp index 2435ac1c33..fc79603e67 100755 --- a/vm/errors.cpp +++ b/vm/errors.cpp @@ -3,26 +3,26 @@ namespace factor { -void factor_vm::out_of_memory() -{ - print_string("Out of memory\n\n"); - dump_generations(); - exit(1); -} - -void fatal_error(const char* msg, cell tagged) +void fatal_error(const char *msg, cell tagged) { print_string("fatal_error: "); print_string(msg); print_string(": "); print_cell_hex(tagged); nl(); exit(1); } -void factor_vm::critical_error(const char* msg, cell tagged) +void critical_error(const char *msg, cell tagged) { print_string("You have triggered a bug in Factor. Please report.\n"); print_string("critical_error: "); print_string(msg); print_string(": "); print_cell_hex(tagged); nl(); - factorbug(); + SIGNAL_VM_PTR()->factorbug(); +} + +void out_of_memory() +{ + print_string("Out of memory\n\n"); + SIGNAL_VM_PTR()->dump_generations(); + exit(1); } void factor_vm::throw_error(cell error, stack_frame *callstack_top) diff --git a/vm/errors.hpp b/vm/errors.hpp index b837381005..c1ea2e1907 100755 --- a/vm/errors.hpp +++ b/vm/errors.hpp @@ -23,7 +23,9 @@ enum vm_error_type ERROR_FP_TRAP, }; -void fatal_error(const char* msg, cell tagged); +void fatal_error(const char *msg, cell tagged); +void critical_error(const char *msg, cell tagged); +void out_of_memory(); void memory_signal_handler_impl(); void fp_signal_handler_impl(); void misc_signal_handler_impl(); diff --git a/vm/heap.cpp b/vm/heap.cpp index 0f2f2fda1f..8c2d7d9ef5 100644 --- a/vm/heap.cpp +++ b/vm/heap.cpp @@ -11,10 +11,9 @@ void heap::clear_free_list() memset(&free,0,sizeof(heap_free_list)); } -heap::heap(factor_vm *myvm_, cell size) +heap::heap(bool secure_gc_, cell size) : secure_gc(secure_gc_) { - myvm = myvm_; - seg = new segment(myvm,align_page(size)); + seg = new segment(align_page(size)); if(!seg) fatal_error("Out of memory in new_heap",size); clear_free_list(); } @@ -85,7 +84,7 @@ void heap::build_free_list(cell size) void heap::assert_free_block(free_heap_block *block) { if(block->type() != FREE_BLOCK_TYPE) - myvm->critical_error("Invalid block in free list",(cell)block); + critical_error("Invalid block in free list",(cell)block); } free_heap_block *heap::find_free_block(cell size) @@ -263,7 +262,7 @@ void heap::compact_heap() heap_block *heap::free_allocated(heap_block *prev, heap_block *scan) { - if(myvm->secure_gc) + if(secure_gc) memset(scan + 1,0,scan->size() - sizeof(heap_block)); if(prev && prev->type() == FREE_BLOCK_TYPE) diff --git a/vm/heap.hpp b/vm/heap.hpp index 07ed6bc291..52d3f98ba5 100644 --- a/vm/heap.hpp +++ b/vm/heap.hpp @@ -10,12 +10,12 @@ struct heap_free_list { }; struct heap { - factor_vm *myvm; + bool secure_gc; segment *seg; heap_free_list free; unordered_map forwarding; - explicit heap(factor_vm *myvm, cell size); + explicit heap(bool secure_gc_, cell size); inline heap_block *next_block(heap_block *block) { diff --git a/vm/image.cpp b/vm/image.cpp index 90afaa82f2..5af8790506 100755 --- a/vm/image.cpp +++ b/vm/image.cpp @@ -28,7 +28,7 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p) clear_gc_stats(); - zone *tenured = &data->generations[data->tenured()]; + zone *tenured = &data->generations[tenured_gen]; fixnum bytes_read = fread((void*)tenured->start,1,h->data_size,file); @@ -85,7 +85,7 @@ bool factor_vm::save_image(const vm_char *filename) return false; } - zone *tenured = &data->generations[data->tenured()]; + zone *tenured = &data->generations[tenured_gen]; h.magic = image_magic; h.version = image_version; @@ -156,7 +156,7 @@ void factor_vm::data_fixup(cell *cell) if(immediate_p(*cell)) return; - zone *tenured = &data->generations[data->tenured()]; + zone *tenured = &data->generations[tenured_gen]; *cell += (tenured->start - data_relocation_base); } @@ -280,7 +280,7 @@ void factor_vm::relocate_data() data_fixup(&bignum_pos_one); data_fixup(&bignum_neg_one); - zone *tenured = &data->generations[data->tenured()]; + zone *tenured = &data->generations[tenured_gen]; for(relocating = tenured->start; relocating < tenured->here; diff --git a/vm/os-unix.cpp b/vm/os-unix.cpp index d17dedf299..e792483e0d 100644 --- a/vm/os-unix.cpp +++ b/vm/os-unix.cpp @@ -83,9 +83,8 @@ void factor_vm::primitive_existsp() box_boolean(stat(path,&sb) >= 0); } -segment::segment(factor_vm *myvm_, cell size_) +segment::segment(cell size_) { - myvm = myvm_; size = size_; int pagesize = getpagesize(); @@ -94,8 +93,7 @@ segment::segment(factor_vm *myvm_, cell size_) PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE,-1,0); - if(array == (char*)-1) - myvm->out_of_memory(); + if(array == (char*)-1) out_of_memory(); if(mprotect(array,pagesize,PROT_NONE) == -1) fatal_error("Cannot protect low guard page",(cell)array); diff --git a/vm/os-windows.cpp b/vm/os-windows.cpp index 0dfaecab69..48ddeffcb6 100755 --- a/vm/os-windows.cpp +++ b/vm/os-windows.cpp @@ -96,9 +96,8 @@ void factor_vm::primitive_existsp() box_boolean(windows_stat(path)); } -segment::segment(factor_vm *myvm_, cell size_) +segment::segment(cell size_) { - myvm = myvm_; size = size_; char *mem; @@ -106,7 +105,7 @@ segment::segment(factor_vm *myvm_, cell size_) if((mem = (char *)VirtualAlloc(NULL, getpagesize() * 2 + size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == 0) - myvm->out_of_memory(); + out_of_memory(); if (!VirtualProtect(mem, getpagesize(), PAGE_NOACCESS, &ignore)) fatal_error("Cannot allocate low guard page", (cell)mem); diff --git a/vm/segments.hpp b/vm/segments.hpp index 6b2e6c69d4..6ff2170974 100644 --- a/vm/segments.hpp +++ b/vm/segments.hpp @@ -9,12 +9,11 @@ inline cell align_page(cell a) /* segments set up guard pages to check for under/overflow. size must be a multiple of the page size */ struct segment { - factor_vm *myvm; cell start; cell size; cell end; - explicit segment(factor_vm *myvm, cell size); + explicit segment(cell size); ~segment(); }; diff --git a/vm/vm.hpp b/vm/vm.hpp index 2ddb991b29..772f8bcfdb 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -4,16 +4,97 @@ namespace factor struct factor_vm { // First five fields accessed directly by assembler. See vm.factor + + /* Current stacks */ context *stack_chain; - zone nursery; /* new objects are allocated here */ + + /* New objects are allocated here */ + zone nursery; + + /* Add this to a shifted address to compute write barrier offsets */ cell cards_offset; cell decks_offset; - cell userenv[USER_ENV]; /* TAGGED user environment data; see getenv/setenv prims */ - // contexts + /* TAGGED user environment data; see getenv/setenv prims */ + cell userenv[USER_ENV]; + + /* Data stack and retain stack sizes */ cell ds_size, rs_size; + + /* Pooling unused contexts to make callbacks cheaper */ context *unused_contexts; + /* Canonical T object. It's just a word */ + cell T; + + /* Is call counting enabled? */ + bool profiling_p; + + /* Global variables used to pass fault handler state from signal handler to + user-space */ + cell signal_number; + cell signal_fault_addr; + unsigned int signal_fpu_status; + stack_frame *signal_callstack_top; + + /* Zeroes out deallocated memory; set by the -securegc command line argument */ + bool secure_gc; + + /* A heap walk allows useful things to be done, like finding all + references to an object for debugging purposes. */ + cell heap_scan_ptr; + + /* GC is off during heap walking */ + bool gc_off; + + /* Data heap */ + data_heap *data; + + /* Where we store object start offsets in cards */ + cell allot_markers_offset; + + /* Only set if we're performing a GC */ + gc_state *current_gc; + + /* Statistics */ + gc_stats stats; + + /* Code heap */ + code_heap *code; + + /* If a runtime function needs to call another function which potentially + allocates memory, it must wrap any local variable references to Factor + objects in gc_root instances */ + std::vector gc_locals; + std::vector gc_bignums; + + /* Debugger */ + bool fep_disabled; + bool full_output; + + /* Canonical bignums */ + cell bignum_zero; + cell bignum_pos_one; + cell bignum_neg_one; + + /* Only used during image loading */ + cell code_relocation_base; + cell data_relocation_base; + + /* Method dispatch statistics */ + cell megamorphic_cache_hits; + cell megamorphic_cache_misses; + + cell cold_call_to_ic_transitions; + cell ic_to_pic_transitions; + cell pic_to_mega_transitions; + /* Indexed by PIC_TAG, PIC_HI_TAG, PIC_TUPLE, PIC_HI_TAG_TUPLE */ + cell pic_counts[4]; + + /* Number of entries in a polymorphic inline cache */ + cell max_pic_size; + + // contexts void reset_datastack(); void reset_retainstack(); void fix_stacks(); @@ -32,9 +113,6 @@ struct factor_vm void primitive_check_datastack(); // run - /* Canonical T object. It's just a word */ - cell T; - void primitive_getenv(); void primitive_setenv(); void primitive_exit(); @@ -46,23 +124,12 @@ struct factor_vm void primitive_clone(); // profiler - bool profiling_p; - void init_profiler(); code_block *compile_profiling_stub(cell word_); void set_profiling(bool profiling); void primitive_profiling(); // errors - /* Global variables used to pass fault handler state from signal handler to - user-space */ - cell signal_number; - cell signal_fault_addr; - unsigned int signal_fpu_status; - stack_frame *signal_callstack_top; - - void out_of_memory(); - void critical_error(const char* msg, cell tagged); void throw_error(cell error, stack_frame *callstack_top); void not_implemented_error(); bool in_page(cell fault, cell area, cell area_size, int offset); @@ -142,13 +209,6 @@ struct factor_vm bignum *digit_stream_to_bignum(unsigned int n_digits, unsigned int (*producer)(unsigned int, factor_vm *), unsigned int radix, int negative_p); //data_heap - bool secure_gc; /* Set by the -securegc command line argument */ - bool gc_off; /* GC is off during heap walking */ - data_heap *data; - /* A heap walk allows useful things to be done, like finding all - references to an object for debugging purposes. */ - cell heap_scan_ptr; - void init_card_decks(); data_heap *grow_data_heap(data_heap *data, cell requested_bytes); void clear_cards(cell gen); @@ -173,8 +233,6 @@ struct factor_vm cell object_size(cell tagged); //write barrier - cell allot_markers_offset; - inline card *addr_to_card(cell a) { return (card*)(((cell)(a) >> card_bits) + cards_offset); @@ -227,15 +285,6 @@ struct factor_vm } // data_gc - /* used during garbage collection only */ - gc_state *current_gc; - /* statistics */ - gc_stats stats[gen_count]; - u64 cards_scanned; - u64 decks_scanned; - u64 card_scan_time; - cell code_heap_scans; - void init_data_gc(); template object *resolve_forwarding(object *untagged, Strategy &strategy); template void trace_handle(cell *handle, Strategy &strategy); @@ -269,7 +318,6 @@ struct factor_vm void clear_gc_stats(); void primitive_become(); void inline_gc(cell *gc_roots_base, cell gc_roots_size); - inline object *allot_zone(zone *z, cell a); object *allot_object(header header, cell size); void primitive_clear_gc_stats(); @@ -301,22 +349,12 @@ struct factor_vm #endif } - // local roots - /* If a runtime function needs to call another function which potentially - allocates memory, it must wrap any local variable references to Factor - objects in gc_root instances */ - std::vector gc_locals; - std::vector gc_bignums; - // generic arrays template Array *allot_array_internal(cell capacity); template bool reallot_array_in_place_p(Array *array, cell capacity); template Array *reallot_array(Array *array_, cell capacity); //debug - bool fep_disabled; - bool full_output; - void print_chars(string* str); void print_word(word* word, cell nesting); void print_factor_string(string* str); @@ -389,10 +427,6 @@ struct factor_vm void primitive_wrapper(); //math - cell bignum_zero; - cell bignum_pos_one; - cell bignum_neg_one; - void primitive_bignum_to_fixnum(); void primitive_float_to_fixnum(); void primitive_fixnum_divint(); @@ -519,8 +553,6 @@ struct factor_vm code_block *add_code_block(cell type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_); //code_heap - code_heap *code; - inline void check_code_pointer(cell ptr) { #ifdef FACTOR_DEBUG @@ -554,9 +586,6 @@ struct factor_vm } //image - cell code_relocation_base; - cell data_relocation_base; - void init_objects(image_header *h); void load_data_heap(FILE *file, image_header *h, vm_parameters *p); void load_code_heap(FILE *file, image_header *h, vm_parameters *p); @@ -646,9 +675,6 @@ struct factor_vm void primitive_quot_compiled_p(); //dispatch - cell megamorphic_cache_hits; - cell megamorphic_cache_misses; - cell search_lookup_alist(cell table, cell klass); cell search_lookup_hash(cell table, cell klass, cell hashcode); cell nth_superclass(tuple_layout *layout, fixnum echelon); @@ -666,12 +692,6 @@ struct factor_vm void primitive_dispatch_stats(); //inline cache - cell max_pic_size; - cell cold_call_to_ic_transitions; - cell ic_to_pic_transitions; - cell pic_to_mega_transitions; - cell pic_counts[4]; /* PIC_TAG, PIC_HI_TAG, PIC_TUPLE, PIC_HI_TAG_TUPLE */ - void init_inline_caching(int max_size); void deallocate_inline_cache(cell return_address); cell determine_inline_cache_type(array *cache_entries); From 3914b0264b3a309ceb4da60850ca9af02b496e0b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 7 Oct 2009 08:40:28 -0500 Subject: [PATCH 22/63] vm: rename a few things --- vm/data_gc.cpp | 24 ++++++++++++------------ vm/data_gc.hpp | 6 +++--- vm/vm.hpp | 8 ++++---- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 0fa5e1b07f..47effccf85 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -71,7 +71,7 @@ template object *factor_vm::promote_object(object *untagged, object *newpointer = strategy.allot(size); if(!newpointer) longjmp(current_gc->gc_unwind,1); - generation_stats *s = &stats.generations[current_gc->collecting_gen]; + generation_statistics *s = &gc_stats.generations[current_gc->collecting_gen]; s->object_count++; s->bytes_copied += size; @@ -91,7 +91,7 @@ template void factor_vm::trace_card(card *ptr, cell gen, cell strategy.copy_reachable_objects(card_scan,&card_end); - stats.cards_scanned++; + gc_stats.cards_scanned++; } template void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy) @@ -122,7 +122,7 @@ template void factor_vm::trace_card_deck(card_deck *deck, cel } } - stats.decks_scanned++; + gc_stats.decks_scanned++; } /* Trace all objects referenced from marked cards */ @@ -201,7 +201,7 @@ template void factor_vm::trace_cards(Strategy &strategy) for(i = current_gc->collecting_gen + 1; i < gen_count; i++) trace_generation_cards(i,strategy); - stats.card_scan_time += (current_micros() - start); + gc_stats.card_scan_time += (current_micros() - start); } /* Copy all tagged pointers in a range of memory */ @@ -353,7 +353,7 @@ template void factor_vm::trace_code_heap_roots(Strategy &stra trace_literal_references(iter->first,strategy); } - stats.code_heap_scans++; + gc_stats.code_heap_scans++; } } @@ -609,7 +609,7 @@ void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_) void factor_vm::record_gc_stats() { - generation_stats *s = &stats.generations[current_gc->collecting_gen]; + generation_statistics *s = &gc_stats.generations[current_gc->collecting_gen]; cell gc_elapsed = (current_micros() - current_gc->start_time); s->collections++; @@ -694,7 +694,7 @@ void factor_vm::primitive_gc_stats() for(i = 0; i < gen_count; i++) { - generation_stats *s = &stats.generations[i]; + generation_statistics *s = &gc_stats.generations[i]; result.add(allot_cell(s->collections)); result.add(tag(long_long_to_bignum(s->gc_time))); result.add(tag(long_long_to_bignum(s->max_gc_time))); @@ -706,10 +706,10 @@ void factor_vm::primitive_gc_stats() } result.add(tag(ulong_long_to_bignum(total_gc_time))); - result.add(tag(ulong_long_to_bignum(stats.cards_scanned))); - result.add(tag(ulong_long_to_bignum(stats.decks_scanned))); - result.add(tag(ulong_long_to_bignum(stats.card_scan_time))); - result.add(allot_cell(stats.code_heap_scans)); + result.add(tag(ulong_long_to_bignum(gc_stats.cards_scanned))); + result.add(tag(ulong_long_to_bignum(gc_stats.decks_scanned))); + result.add(tag(ulong_long_to_bignum(gc_stats.card_scan_time))); + result.add(allot_cell(gc_stats.code_heap_scans)); result.trim(); dpush(result.elements.value()); @@ -717,7 +717,7 @@ void factor_vm::primitive_gc_stats() void factor_vm::clear_gc_stats() { - memset(&stats,0,sizeof(gc_stats)); + memset(&gc_stats,0,sizeof(gc_statistics)); } void factor_vm::primitive_clear_gc_stats() diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index 04a9682ae5..68aab2f6b3 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -2,7 +2,7 @@ namespace factor { /* statistics */ -struct generation_stats { +struct generation_statistics { cell collections; u64 gc_time; u64 max_gc_time; @@ -10,8 +10,8 @@ struct generation_stats { u64 bytes_copied; }; -struct gc_stats { - generation_stats generations[gen_count]; +struct gc_statistics { + generation_statistics generations[gen_count]; u64 cards_scanned; u64 decks_scanned; u64 card_scan_time; diff --git a/vm/vm.hpp b/vm/vm.hpp index 772f8bcfdb..0ad1303156 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -50,6 +50,9 @@ struct factor_vm /* Data heap */ data_heap *data; + /* Code heap */ + code_heap *code; + /* Where we store object start offsets in cards */ cell allot_markers_offset; @@ -57,10 +60,7 @@ struct factor_vm gc_state *current_gc; /* Statistics */ - gc_stats stats; - - /* Code heap */ - code_heap *code; + gc_statistics gc_stats; /* If a runtime function needs to call another function which potentially allocates memory, it must wrap any local variable references to Factor From 18bd437e3f42dbad802fee077b387c0827970cf9 Mon Sep 17 00:00:00 2001 From: Phil Dawes Date: Wed, 7 Oct 2009 19:18:29 +0100 Subject: [PATCH 23/63] disassemble can handle anonymous quotations --- basis/tools/disassembler/disassembler.factor | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/basis/tools/disassembler/disassembler.factor b/basis/tools/disassembler/disassembler.factor index 16408c0eb8..4aec909e88 100755 --- a/basis/tools/disassembler/disassembler.factor +++ b/basis/tools/disassembler/disassembler.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: alien alien.c-types arrays byte-arrays combinators -destructors generic io kernel libc math sequences system tr -vocabs.loader words alien.data ; +USING: alien alien.data arrays byte-arrays compiler.units destructors +io kernel libc math quotations sequences stack-checker system tr +vocabs.loader words ; IN: tools.disassembler GENERIC: disassemble ( obj -- ) @@ -24,6 +24,8 @@ M: pair disassemble first2 disassemble* [ tabs>spaces print ] each ; M: word disassemble word-xt 2array disassemble ; +M: quotation disassemble [ dup infer define-temp ] with-compilation-unit disassemble ; + cpu x86? "tools.disassembler.udis" "tools.disassembler.gdb" ? From 651a7fb6fa8ca9bea3eb828cd94d746d19ab6f0b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 7 Oct 2009 11:59:59 -0500 Subject: [PATCH 24/63] vm: replace generations array with individual instance variables referencing zone objects --- .../concatenative/concatenative.factor | 2 +- vm/code_heap.cpp | 1 + vm/data_gc.cpp | 82 +++++--------- vm/data_heap.cpp | 105 +++++++++--------- vm/data_heap.hpp | 41 ++----- vm/debug.cpp | 22 +--- vm/gc/zone.hpp | 33 ++++++ vm/image.cpp | 23 ++-- vm/master.hpp | 1 + vm/vm.hpp | 18 ++- 10 files changed, 144 insertions(+), 184 deletions(-) create mode 100644 vm/gc/zone.hpp diff --git a/extra/websites/concatenative/concatenative.factor b/extra/websites/concatenative/concatenative.factor index b5a29073cd..11b30a114c 100644 --- a/extra/websites/concatenative/concatenative.factor +++ b/extra/websites/concatenative/concatenative.factor @@ -97,7 +97,7 @@ SYMBOL: dh-file test-db "concatenative.org" add-responder test-db "paste.factorcode.org" add-responder test-db "planet.factorcode.org" add-responder - home "docs" append-path test-db "docs.factorcode.org" add-responder + home "docs" append-path "docs.factorcode.org" add-responder home "cgi" append-path "gitweb.factorcode.org" add-responder "builds.factorcode.org" add-responder main-responder set-global ; diff --git a/vm/code_heap.cpp b/vm/code_heap.cpp index f07639d9bb..6a5391a589 100755 --- a/vm/code_heap.cpp +++ b/vm/code_heap.cpp @@ -27,6 +27,7 @@ void code_heap::code_heap_free(code_block *compiled) void factor_vm::init_code_heap(cell size) { code = new code_heap(secure_gc,size); + code->youngest_referenced_generation = nursery_gen; } bool factor_vm::in_code_heap_p(cell ptr) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 47effccf85..b3836e4a3b 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -3,11 +3,6 @@ namespace factor { -void factor_vm::init_data_gc() -{ - code->youngest_referenced_generation = nursery_gen; -} - gc_state::gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_gen_) : data(data_), growing_data_heap(growing_data_heap_), @@ -81,26 +76,23 @@ template object *factor_vm::promote_object(object *untagged, return newpointer; } -template void factor_vm::trace_card(card *ptr, cell gen, cell here, Strategy &strategy) +template void factor_vm::trace_card(card *ptr, cell here, Strategy &strategy) { cell card_scan = card_to_addr(ptr) + card_offset(ptr); cell card_end = card_to_addr(ptr + 1); - if(here < card_end) - card_end = here; + if(here < card_end) card_end = here; strategy.copy_reachable_objects(card_scan,&card_end); gc_stats.cards_scanned++; } -template void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy) +template void factor_vm::trace_card_deck(card_deck *deck, cell here, card mask, card unmask, Strategy &strategy) { card *first_card = deck_to_card(deck); card *last_card = deck_to_card(deck + 1); - cell here = data->generations[gen].here; - u32 *quad_ptr; u32 quad_mask = mask | (mask << 8) | (mask << 16) | (mask << 24); @@ -115,7 +107,7 @@ template void factor_vm::trace_card_deck(card_deck *deck, cel { if(ptr[card] & mask) { - trace_card(&ptr[card],gen,here,strategy); + trace_card(&ptr[card],here,strategy); ptr[card] &= ~unmask; } } @@ -126,10 +118,12 @@ template void factor_vm::trace_card_deck(card_deck *deck, cel } /* Trace all objects referenced from marked cards */ -template void factor_vm::trace_generation_cards(cell gen, Strategy &strategy) +template void factor_vm::trace_cards(cell gen, zone *z, Strategy &strategy) { - card_deck *first_deck = addr_to_deck(data->generations[gen].start); - card_deck *last_deck = addr_to_deck(data->generations[gen].end); + u64 start_time = current_micros(); + + card_deck *first_deck = addr_to_deck(z->start); + card_deck *last_deck = addr_to_deck(z->end); card mask, unmask; @@ -185,23 +179,12 @@ template void factor_vm::trace_generation_cards(cell gen, Str { if(*ptr & mask) { - trace_card_deck(ptr,gen,mask,unmask,strategy); + trace_card_deck(ptr,z->here,mask,unmask,strategy); *ptr &= ~unmask; } } -} -/* Scan cards in all generations older than the one being collected, copying -old->new references */ -template void factor_vm::trace_cards(Strategy &strategy) -{ - u64 start = current_micros(); - - cell i; - for(i = current_gc->collecting_gen + 1; i < gen_count; i++) - trace_generation_cards(i,strategy); - - gc_stats.card_scan_time += (current_micros() - start); + gc_stats.card_scan_time += (current_micros() - start_time); } /* Copy all tagged pointers in a range of memory */ @@ -482,7 +465,7 @@ struct aging_collector : copying_collector explicit aging_collector(factor_vm *myvm_, zone *newspace_) : copying_collector(myvm_,newspace_), - tenured(&myvm->data->generations[tenured_gen]) {} + tenured(myvm->data->tenured) {} bool should_copy_p(object *untagged) { @@ -536,11 +519,12 @@ struct tenured_collector : copying_collector void factor_vm::collect_nursery() { - nursery_collector collector(this,&data->generations[aging_gen]); + nursery_collector collector(this,data->aging); trace_roots(collector); trace_contexts(collector); - trace_cards(collector); + trace_cards(tenured_gen,data->tenured,collector); + trace_cards(aging_gen,data->aging,collector); trace_code_heap_roots(collector); collector.go(); update_dirty_code_blocks(); @@ -550,14 +534,14 @@ void factor_vm::collect_nursery() void factor_vm::collect_aging() { - std::swap(data->generations[aging_gen],data->semispaces[aging_gen]); - reset_generation(aging_gen); + std::swap(data->aging,data->aging_semispace); + reset_generation(data->aging); - aging_collector collector(this,&data->generations[aging_gen]); + aging_collector collector(this,data->aging); trace_roots(collector); trace_contexts(collector); - trace_cards(collector); + trace_cards(tenured_gen,data->tenured,collector); trace_code_heap_roots(collector); collector.go(); update_dirty_code_blocks(); @@ -567,16 +551,16 @@ void factor_vm::collect_aging() void factor_vm::collect_aging_again() { - aging_again_collector collector(this,&data->generations[tenured_gen]); + aging_again_collector collector(this,data->tenured); trace_roots(collector); trace_contexts(collector); - trace_cards(collector); + trace_cards(tenured_gen,data->tenured,collector); trace_code_heap_roots(collector); collector.go(); update_dirty_code_blocks(); - reset_generation(aging_gen); + reset_generation(data->aging); nursery.here = nursery.start; } @@ -589,18 +573,18 @@ void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_) } else { - std::swap(data->generations[tenured_gen],data->semispaces[tenured_gen]); - reset_generation(tenured_gen); + std::swap(data->tenured,data->tenured_semispace); + reset_generation(data->tenured); } - tenured_collector collector(this,&data->generations[tenured_gen]); + tenured_collector collector(this,data->tenured); trace_roots(collector); if(trace_contexts_) trace_contexts(collector); collector.go(); free_unmarked_code_blocks(); - reset_generation(aging_gen); + reset_generation(data->aging); nursery.here = nursery.start; if(current_gc->growing_data_heap) @@ -798,23 +782,15 @@ object *factor_vm::allot_object(header header, cell size) tenured space */ else { - zone *tenured = &data->generations[tenured_gen]; - /* If tenured space does not have enough room, collect */ - if(tenured->here + size > tenured->end) - { + if(data->tenured->here + size > data->tenured->end) gc(); - tenured = &data->generations[tenured_gen]; - } /* If it still won't fit, grow the heap */ - if(tenured->here + size > tenured->end) - { + if(data->tenured->here + size > data->tenured->end) garbage_collection(tenured_gen,true,true,size); - tenured = &data->generations[tenured_gen]; - } - obj = tenured->allot(size); + obj = data->tenured->allot(size); allot_barrier(obj); /* Allows initialization code to store old->new pointers diff --git a/vm/data_heap.cpp b/vm/data_heap.cpp index 5ccde31f37..4fc9770c55 100755 --- a/vm/data_heap.cpp +++ b/vm/data_heap.cpp @@ -27,12 +27,7 @@ data_heap::data_heap(factor_vm *myvm, cell young_size_, cell aging_size_, cell t seg = new segment(total_size); - generations = new zone[gen_count]; - semispaces = new zone[gen_count]; - cell cards_size = total_size >> card_bits; - allot_markers = new char[cards_size]; - allot_markers_end = allot_markers + cards_size; cards = new char[cards_size]; cards_end = cards + cards_size; @@ -41,21 +36,41 @@ data_heap::data_heap(factor_vm *myvm, cell young_size_, cell aging_size_, cell t decks = new char[decks_size]; decks_end = decks + decks_size; + allot_markers = new char[cards_size]; + allot_markers_end = allot_markers + cards_size; + cell alloter = align(seg->start,deck_size); - alloter = generations[tenured_gen].init_zone(tenured_size,alloter); - alloter = semispaces[tenured_gen].init_zone(tenured_size,alloter); + tenured = new zone; + tenured_semispace = new zone; + alloter = tenured->init_zone(tenured_size,alloter); + alloter = tenured_semispace->init_zone(tenured_size,alloter); - alloter = generations[aging_gen].init_zone(aging_size,alloter); - alloter = semispaces[aging_gen].init_zone(aging_size,alloter); + aging = new zone; + aging_semispace = new zone; + alloter = aging->init_zone(aging_size,alloter); + alloter = aging_semispace->init_zone(aging_size,alloter); - alloter = generations[nursery_gen].init_zone(young_size,alloter); - alloter = semispaces[nursery_gen].init_zone(0,alloter); + nursery = new zone; + alloter = nursery->init_zone(young_size,alloter); if(seg->end - alloter > deck_size) critical_error("Bug in alloc_data_heap",alloter); } +data_heap::~data_heap() +{ + delete seg; + delete nursery; + delete aging; + delete aging_semispace; + delete tenured; + delete tenured_semispace; + delete[] allot_markers; + delete[] cards; + delete[] decks; +} + data_heap *factor_vm::grow_data_heap(data_heap *data, cell requested_bytes) { cell new_tenured_size = (data->tenured_size * 2) + requested_bytes; @@ -66,48 +81,35 @@ data_heap *factor_vm::grow_data_heap(data_heap *data, cell requested_bytes) new_tenured_size); } -data_heap::~data_heap() -{ - delete seg; - delete[] generations; - delete[] semispaces; - delete[] allot_markers; - delete[] cards; - delete[] decks; -} - -void factor_vm::clear_cards(cell gen) +void factor_vm::clear_cards(zone *gen) { /* NOTE: reverse order due to heap layout. */ - card *first_card = addr_to_card(data->generations[gen].start); - card *last_card = addr_to_card(data->generations[gen].end); + card *first_card = addr_to_card(gen->start); + card *last_card = addr_to_card(gen->end); memset(first_card,0,last_card - first_card); } -void factor_vm::clear_decks(cell gen) +void factor_vm::clear_decks(zone *gen) { /* NOTE: reverse order due to heap layout. */ - card_deck *first_deck = addr_to_deck(data->generations[gen].start); - card_deck *last_deck = addr_to_deck(data->generations[gen].end); + card_deck *first_deck = addr_to_deck(gen->start); + card_deck *last_deck = addr_to_deck(gen->end); memset(first_deck,0,last_deck - first_deck); } -void factor_vm::clear_allot_markers(cell gen) +void factor_vm::clear_allot_markers(zone *gen) { - card *first_card = addr_to_allot_marker((object *)data->generations[gen].start); - card *last_card = addr_to_allot_marker((object *)data->generations[gen].end); + card *first_card = addr_to_allot_marker((object *)gen->start); + card *last_card = addr_to_allot_marker((object *)gen->end); memset(first_card,invalid_allot_marker,last_card - first_card); } /* After garbage collection, any generations which are now empty need to have their allocation pointers and cards reset. */ -void factor_vm::reset_generation(cell gen) +void factor_vm::reset_generation(zone *gen) { - assert(gen != nursery_gen); - - zone *z = &data->generations[gen]; - z->here = z->start; - if(secure_gc) memset((void*)z->start,69,z->size); + gen->here = gen->start; + if(secure_gc) memset((void*)gen->start,69,gen->size); clear_cards(gen); clear_decks(gen); @@ -117,18 +119,17 @@ void factor_vm::reset_generation(cell gen) void factor_vm::set_data_heap(data_heap *data_) { data = data_; - nursery = data->generations[nursery_gen]; + nursery = *data->nursery; nursery.here = nursery.start; init_card_decks(); - reset_generation(aging_gen); - reset_generation(tenured_gen); + reset_generation(data->aging); + reset_generation(data->tenured); } void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_) { set_data_heap(new data_heap(this,young_size,aging_size,tenured_size)); secure_gc = secure_gc_; - init_data_gc(); } /* Size of the object pointed to by a tagged pointer */ @@ -231,13 +232,14 @@ void factor_vm::primitive_data_room() growable_array a(this); - cell gen; - for(gen = 0; gen < gen_count; gen++) - { - zone *z = (gen == nursery_gen ? &nursery : &data->generations[gen]); - a.add(tag_fixnum((z->end - z->here) >> 10)); - a.add(tag_fixnum((z->size) >> 10)); - } + a.add(tag_fixnum((nursery.end - nursery.here) >> 10)); + a.add(tag_fixnum((nursery.size) >> 10)); + + a.add(tag_fixnum((data->aging->end - data->aging->here) >> 10)); + a.add(tag_fixnum((data->aging->size) >> 10)); + + a.add(tag_fixnum((data->tenured->end - data->tenured->here) >> 10)); + a.add(tag_fixnum((data->tenured->size) >> 10)); a.trim(); dpush(a.elements.value()); @@ -246,7 +248,7 @@ void factor_vm::primitive_data_room() /* Disables GC and activates next-object ( -- obj ) primitive */ void factor_vm::begin_scan() { - heap_scan_ptr = data->generations[tenured_gen].start; + heap_scan_ptr = data->tenured->start; gc_off = true; } @@ -265,7 +267,7 @@ cell factor_vm::next_object() if(!gc_off) general_error(ERROR_HEAP_SCAN,F,F,NULL); - if(heap_scan_ptr >= data->generations[tenured_gen].here) + if(heap_scan_ptr >= data->tenured->here) return F; object *obj = (object *)heap_scan_ptr; @@ -294,9 +296,6 @@ template void factor_vm::each_object(Iterator &iterator) end_scan(); } -namespace -{ - struct word_counter { cell count; explicit word_counter() : count(0) {} @@ -309,8 +308,6 @@ struct word_accumulator { void operator()(tagged obj) { if(obj.type_p(WORD_TYPE)) words.add(obj.value()); } }; -} - cell factor_vm::find_all_words() { word_counter counter; diff --git a/vm/data_heap.hpp b/vm/data_heap.hpp index cd53d66768..891d1361ed 100755 --- a/vm/data_heap.hpp +++ b/vm/data_heap.hpp @@ -1,45 +1,18 @@ namespace factor { -/* generational copying GC divides memory into zones */ -struct zone { - /* allocation pointer is 'here'; its offset is hardcoded in the - compiler backends */ - cell start; - cell here; - cell size; - cell end; - - cell init_zone(cell size_, cell start_) - { - size = size_; - start = here = start_; - end = start_ + size_; - return end; - } - - inline bool contains_p(object *pointer) - { - return ((cell)pointer - start) < size; - } - - inline object *allot(cell size) - { - cell h = here; - here = h + align8(size); - return (object *)h; - } -}; - struct data_heap { - segment *seg; - cell young_size; cell aging_size; cell tenured_size; - zone *generations; - zone *semispaces; + segment *seg; + + zone *nursery; + zone *aging; + zone *aging_semispace; + zone *tenured; + zone *tenured_semispace; char *allot_markers; char *allot_markers_end; diff --git a/vm/debug.cpp b/vm/debug.cpp index e1c1fa5a85..5460a309fd 100755 --- a/vm/debug.cpp +++ b/vm/debug.cpp @@ -211,8 +211,9 @@ void factor_vm::dump_memory(cell from, cell to) dump_cell(from); } -void factor_vm::dump_zone(zone *z) +void factor_vm::dump_zone(cell gen, zone *z) { + print_string("Generation "); print_cell(gen); print_string(": "); print_string("Start="); print_cell(z->start); print_string(", size="); print_cell(z->size); print_string(", here="); print_cell(z->here - z->start); nl(); @@ -220,22 +221,9 @@ void factor_vm::dump_zone(zone *z) void factor_vm::dump_generations() { - cell i; - - print_string("Nursery: "); - dump_zone(&nursery); - - for(i = 1; i < gen_count; i++) - { - print_string("Generation "); print_cell(i); print_string(": "); - dump_zone(&data->generations[i]); - } - - for(i = 0; i < gen_count; i++) - { - print_string("Semispace "); print_cell(i); print_string(": "); - dump_zone(&data->semispaces[i]); - } + dump_zone(nursery_gen,&nursery); + dump_zone(aging_gen,data->aging); + dump_zone(tenured_gen,data->tenured); print_string("Cards: base="); print_cell((cell)data->cards); diff --git a/vm/gc/zone.hpp b/vm/gc/zone.hpp new file mode 100644 index 0000000000..a05afd45c6 --- /dev/null +++ b/vm/gc/zone.hpp @@ -0,0 +1,33 @@ +namespace factor +{ + +struct zone { + /* allocation pointer is 'here'; its offset is hardcoded in the + compiler backends */ + cell start; + cell here; + cell size; + cell end; + + cell init_zone(cell size_, cell start_) + { + size = size_; + start = here = start_; + end = start_ + size_; + return end; + } + + inline bool contains_p(object *pointer) + { + return ((cell)pointer - start) < size; + } + + inline object *allot(cell size) + { + cell h = here; + here = h + align8(size); + return (object *)h; + } +}; + +} diff --git a/vm/image.cpp b/vm/image.cpp index 5af8790506..9a70937508 100755 --- a/vm/image.cpp +++ b/vm/image.cpp @@ -28,9 +28,7 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p) clear_gc_stats(); - zone *tenured = &data->generations[tenured_gen]; - - fixnum bytes_read = fread((void*)tenured->start,1,h->data_size,file); + fixnum bytes_read = fread((void*)data->tenured->start,1,h->data_size,file); if((cell)bytes_read != h->data_size) { @@ -42,7 +40,7 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p) fatal_error("load_data_heap failed",0); } - tenured->here = tenured->start + h->data_size; + data->tenured->here = data->tenured->start + h->data_size; data_relocation_base = h->data_relocation_base; } @@ -85,12 +83,10 @@ bool factor_vm::save_image(const vm_char *filename) return false; } - zone *tenured = &data->generations[tenured_gen]; - h.magic = image_magic; h.version = image_version; - h.data_relocation_base = tenured->start; - h.data_size = tenured->here - tenured->start; + 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(); @@ -105,7 +101,7 @@ bool factor_vm::save_image(const vm_char *filename) bool ok = true; if(fwrite(&h,sizeof(image_header),1,file) != 1) ok = false; - if(fwrite((void*)tenured->start,h.data_size,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; @@ -156,8 +152,7 @@ void factor_vm::data_fixup(cell *cell) if(immediate_p(*cell)) return; - zone *tenured = &data->generations[tenured_gen]; - *cell += (tenured->start - data_relocation_base); + *cell += (data->tenured->start - data_relocation_base); } template void factor_vm::code_fixup(Type **handle) @@ -280,10 +275,8 @@ void factor_vm::relocate_data() data_fixup(&bignum_pos_one); data_fixup(&bignum_neg_one); - zone *tenured = &data->generations[tenured_gen]; - - for(relocating = tenured->start; - relocating < tenured->here; + for(relocating = data->tenured->start; + relocating < data->tenured->here; relocating += untagged_object_size((object *)relocating)) { object *obj = (object *)relocating; diff --git a/vm/master.hpp b/vm/master.hpp index 457dbee0ab..d942c1a3ac 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -69,6 +69,7 @@ namespace factor #include "bignumint.hpp" #include "bignum.hpp" #include "code_block.hpp" +#include "gc/zone.hpp" #include "data_heap.hpp" #include "write_barrier.hpp" #include "data_gc.hpp" diff --git a/vm/vm.hpp b/vm/vm.hpp index 0ad1303156..9836342fe2 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -211,10 +211,10 @@ struct factor_vm //data_heap void init_card_decks(); data_heap *grow_data_heap(data_heap *data, cell requested_bytes); - void clear_cards(cell gen); - void clear_decks(cell gen); - void clear_allot_markers(cell gen); - void reset_generation(cell gen); + void clear_cards(zone *gen); + void clear_decks(zone *gen); + void clear_allot_markers(zone *gen); + void reset_generation(zone *gen); void set_data_heap(data_heap *data_); void init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_); cell untagged_object_size(object *pointer); @@ -285,15 +285,13 @@ struct factor_vm } // data_gc - void init_data_gc(); template object *resolve_forwarding(object *untagged, Strategy &strategy); template void trace_handle(cell *handle, Strategy &strategy); template object *promote_object(object *pointer, Strategy &strategy); template void trace_slots(object *ptr, Strategy &strategy); - template void trace_card(card *ptr, cell gen, cell here, Strategy &strategy); - template void trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy); - template void trace_generation_cards(cell gen, Strategy &strategy); - template void trace_cards(Strategy &strategy); + template void trace_card(card *ptr, cell here, Strategy &strategy); + template void trace_card_deck(card_deck *deck, cell here, card mask, card unmask, Strategy &strategy); + template void trace_cards(cell gen, zone *z, Strategy &strategy); template void trace_stack_elements(segment *region, cell top, Strategy &strategy); template void trace_registered_locals(Strategy &strategy); template void trace_registered_bignums(Strategy &strategy); @@ -368,7 +366,7 @@ struct factor_vm void print_callstack(); void dump_cell(cell x); void dump_memory(cell from, cell to); - void dump_zone(zone *z); + void dump_zone(cell gen, zone *z); void dump_generations(); void dump_objects(cell type); void find_data_references_step(cell *scan); From 23e133e383869251f0e9c4942a20bbf6baf198f5 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 7 Oct 2009 14:05:09 -0500 Subject: [PATCH 25/63] vm: make a new old_space type to encapsulate a few things, split up generations array somewhat --- Makefile | 4 +-- vm/data_gc.cpp | 55 +++++++++++++++++---------------------- vm/data_gc.hpp | 4 +-- vm/data_heap.cpp | 40 ++++++++-------------------- vm/data_heap.hpp | 11 +++----- vm/image.cpp | 2 +- vm/local_roots.cpp | 5 ---- vm/master.hpp | 5 ++-- vm/old_space.hpp | 62 ++++++++++++++++++++++++++++++++++++++++++++ vm/vm.cpp | 1 + vm/vm.hpp | 34 +++++------------------- vm/write_barrier.cpp | 4 --- vm/{gc => }/zone.hpp | 0 13 files changed, 115 insertions(+), 112 deletions(-) delete mode 100644 vm/local_roots.cpp create mode 100644 vm/old_space.hpp delete mode 100644 vm/write_barrier.cpp rename vm/{gc => }/zone.hpp (100%) diff --git a/Makefile b/Makefile index dd2e83985e..4c50787f2d 100755 --- a/Makefile +++ b/Makefile @@ -51,7 +51,6 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \ vm/inline_cache.o \ vm/io.o \ vm/jit.o \ - vm/local_roots.o \ vm/math.o \ vm/primitives.o \ vm/profiler.o \ @@ -61,8 +60,7 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \ vm/tuples.o \ vm/utilities.o \ vm/vm.o \ - vm/words.o \ - vm/write_barrier.o + vm/words.o EXE_OBJS = $(PLAF_EXE_OBJS) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index b3836e4a3b..dfe5ef3365 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -76,19 +76,20 @@ template object *factor_vm::promote_object(object *untagged, return newpointer; } -template void factor_vm::trace_card(card *ptr, cell here, Strategy &strategy) +template void factor_vm::trace_card(card *ptr, old_space *gen, Strategy &strategy) { - cell card_scan = card_to_addr(ptr) + card_offset(ptr); + cell card_start = card_to_addr(ptr); + cell card_scan = card_start + gen->card_offset(card_start); cell card_end = card_to_addr(ptr + 1); - if(here < card_end) card_end = here; + if(gen->here < card_end) card_end = gen->here; strategy.copy_reachable_objects(card_scan,&card_end); gc_stats.cards_scanned++; } -template void factor_vm::trace_card_deck(card_deck *deck, cell here, card mask, card unmask, Strategy &strategy) +template void factor_vm::trace_card_deck(card_deck *deck, old_space *gen, card mask, card unmask, Strategy &strategy) { card *first_card = deck_to_card(deck); card *last_card = deck_to_card(deck + 1); @@ -107,7 +108,7 @@ template void factor_vm::trace_card_deck(card_deck *deck, cel { if(ptr[card] & mask) { - trace_card(&ptr[card],here,strategy); + trace_card(&ptr[card],gen,strategy); ptr[card] &= ~unmask; } } @@ -118,7 +119,7 @@ template void factor_vm::trace_card_deck(card_deck *deck, cel } /* Trace all objects referenced from marked cards */ -template void factor_vm::trace_cards(cell gen, zone *z, Strategy &strategy) +template void factor_vm::trace_cards(cell gen, old_space *z, Strategy &strategy) { u64 start_time = current_micros(); @@ -179,7 +180,7 @@ template void factor_vm::trace_cards(cell gen, zone *z, Strat { if(*ptr & mask) { - trace_card_deck(ptr,z->here,mask,unmask,strategy); + trace_card_deck(ptr,z,mask,unmask,strategy); *ptr &= ~unmask; } } @@ -398,10 +399,10 @@ void factor_vm::update_dirty_code_blocks() } template -copying_collector::copying_collector(factor_vm *myvm_, zone *newspace_) -: myvm(myvm_), current_gc(myvm_->current_gc), newspace(newspace_) +copying_collector::copying_collector(factor_vm *myvm_, old_space *target_) +: myvm(myvm_), current_gc(myvm_->current_gc), target(target_) { - scan = newspace->here; + scan = target->here; } template Strategy ©ing_collector::strategy() @@ -411,14 +412,7 @@ template Strategy ©ing_collector::strategy() template object *copying_collector::allot(cell size) { - if(newspace->here + size <= newspace->end) - { - object *obj = newspace->allot(size); - myvm->allot_barrier(obj); - return obj; - } - else - return NULL; + return target->allot(size); } template object *copying_collector::copy_object(object *untagged) @@ -440,13 +434,13 @@ template cell copying_collector::trace_next(cell sc template void copying_collector::go() { - strategy().copy_reachable_objects(scan,&newspace->here); + strategy().copy_reachable_objects(scan,&target->here); } struct nursery_collector : copying_collector { - explicit nursery_collector(factor_vm *myvm_, zone *newspace_) : - copying_collector(myvm_,newspace_) {} + explicit nursery_collector(factor_vm *myvm_, old_space *target_) : + copying_collector(myvm_,target_) {} bool should_copy_p(object *untagged) { @@ -463,13 +457,13 @@ struct aging_collector : copying_collector { zone *tenured; - explicit aging_collector(factor_vm *myvm_, zone *newspace_) : - copying_collector(myvm_,newspace_), + explicit aging_collector(factor_vm *myvm_, old_space *target_) : + copying_collector(myvm_,target_), tenured(myvm->data->tenured) {} bool should_copy_p(object *untagged) { - if(newspace->contains_p(untagged)) + if(target->contains_p(untagged)) return false; else return !tenured->contains_p(untagged); @@ -483,12 +477,12 @@ struct aging_collector : copying_collector struct aging_again_collector : copying_collector { - explicit aging_again_collector(factor_vm *myvm_, zone *newspace_) : - copying_collector(myvm_,newspace_) {} + explicit aging_again_collector(factor_vm *myvm_, old_space *target_) : + copying_collector(myvm_,target_) {} bool should_copy_p(object *untagged) { - return !newspace->contains_p(untagged); + return !target->contains_p(untagged); } void copy_reachable_objects(cell scan, cell *end) @@ -499,12 +493,12 @@ struct aging_again_collector : copying_collector struct tenured_collector : copying_collector { - explicit tenured_collector(factor_vm *myvm_, zone *newspace_) : - copying_collector(myvm_,newspace_) {} + explicit tenured_collector(factor_vm *myvm_, old_space *target_) : + copying_collector(myvm_,target_) {} bool should_copy_p(object *untagged) { - return !newspace->contains_p(untagged); + return !target->contains_p(untagged); } void copy_reachable_objects(cell scan, cell *end) @@ -791,7 +785,6 @@ object *factor_vm::allot_object(header header, cell size) garbage_collection(tenured_gen,true,true,size); obj = data->tenured->allot(size); - allot_barrier(obj); /* Allows initialization code to store old->new pointers without hitting the write barrier in the common case of diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index 68aab2f6b3..9032f6696d 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -66,10 +66,10 @@ struct gc_state { template struct copying_collector { factor_vm *myvm; gc_state *current_gc; - zone *newspace; + old_space *target; cell scan; - explicit copying_collector(factor_vm *myvm_, zone *newspace); + explicit copying_collector(factor_vm *myvm_, old_space *target); Strategy &strategy(); object *allot(cell size); cell trace_next(cell scan); diff --git a/vm/data_heap.cpp b/vm/data_heap.cpp index 4fc9770c55..7e358cb2f9 100755 --- a/vm/data_heap.cpp +++ b/vm/data_heap.cpp @@ -6,7 +6,6 @@ namespace factor void factor_vm::init_card_decks() { cell start = align(data->seg->start,deck_size); - allot_markers_offset = (cell)data->allot_markers - (start >> card_bits); cards_offset = (cell)data->cards - (start >> card_bits); decks_offset = (cell)data->decks - (start >> deck_bits); } @@ -36,26 +35,17 @@ data_heap::data_heap(factor_vm *myvm, cell young_size_, cell aging_size_, cell t decks = new char[decks_size]; decks_end = decks + decks_size; - allot_markers = new char[cards_size]; - allot_markers_end = allot_markers + cards_size; + cell start = align(seg->start,deck_size); - cell alloter = align(seg->start,deck_size); + tenured = new old_space(tenured_size,start); + tenured_semispace = new old_space(tenured_size,tenured->end); - tenured = new zone; - tenured_semispace = new zone; - alloter = tenured->init_zone(tenured_size,alloter); - alloter = tenured_semispace->init_zone(tenured_size,alloter); + aging = new old_space(aging_size,tenured_semispace->end); + aging_semispace = new old_space(aging_size,aging->end); - aging = new zone; - aging_semispace = new zone; - alloter = aging->init_zone(aging_size,alloter); - alloter = aging_semispace->init_zone(aging_size,alloter); + nursery = new zone(young_size,aging_semispace->end); - nursery = new zone; - alloter = nursery->init_zone(young_size,alloter); - - if(seg->end - alloter > deck_size) - critical_error("Bug in alloc_data_heap",alloter); + assert(seg->end - nursery->end <= deck_size); } data_heap::~data_heap() @@ -66,7 +56,6 @@ data_heap::~data_heap() delete aging_semispace; delete tenured; delete tenured_semispace; - delete[] allot_markers; delete[] cards; delete[] decks; } @@ -81,7 +70,7 @@ data_heap *factor_vm::grow_data_heap(data_heap *data, cell requested_bytes) new_tenured_size); } -void factor_vm::clear_cards(zone *gen) +void factor_vm::clear_cards(old_space *gen) { /* NOTE: reverse order due to heap layout. */ card *first_card = addr_to_card(gen->start); @@ -89,7 +78,7 @@ void factor_vm::clear_cards(zone *gen) memset(first_card,0,last_card - first_card); } -void factor_vm::clear_decks(zone *gen) +void factor_vm::clear_decks(old_space *gen) { /* NOTE: reverse order due to heap layout. */ card_deck *first_deck = addr_to_deck(gen->start); @@ -97,23 +86,16 @@ void factor_vm::clear_decks(zone *gen) memset(first_deck,0,last_deck - first_deck); } -void factor_vm::clear_allot_markers(zone *gen) -{ - card *first_card = addr_to_allot_marker((object *)gen->start); - card *last_card = addr_to_allot_marker((object *)gen->end); - memset(first_card,invalid_allot_marker,last_card - first_card); -} - /* After garbage collection, any generations which are now empty need to have their allocation pointers and cards reset. */ -void factor_vm::reset_generation(zone *gen) +void factor_vm::reset_generation(old_space *gen) { gen->here = gen->start; if(secure_gc) memset((void*)gen->start,69,gen->size); clear_cards(gen); clear_decks(gen); - clear_allot_markers(gen); + gen->clear_allot_markers(); } void factor_vm::set_data_heap(data_heap *data_) diff --git a/vm/data_heap.hpp b/vm/data_heap.hpp index 891d1361ed..3f620e3d42 100755 --- a/vm/data_heap.hpp +++ b/vm/data_heap.hpp @@ -9,13 +9,10 @@ struct data_heap { segment *seg; zone *nursery; - zone *aging; - zone *aging_semispace; - zone *tenured; - zone *tenured_semispace; - - char *allot_markers; - char *allot_markers_end; + old_space *aging; + old_space *aging_semispace; + old_space *tenured; + old_space *tenured_semispace; char *cards; char *cards_end; diff --git a/vm/image.cpp b/vm/image.cpp index 9a70937508..272309063b 100755 --- a/vm/image.cpp +++ b/vm/image.cpp @@ -280,7 +280,7 @@ void factor_vm::relocate_data() relocating += untagged_object_size((object *)relocating)) { object *obj = (object *)relocating; - allot_barrier(obj); + data->tenured->record_allocation(obj); relocate_object(obj); } } diff --git a/vm/local_roots.cpp b/vm/local_roots.cpp deleted file mode 100644 index 71baee6deb..0000000000 --- a/vm/local_roots.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "master.hpp" - -namespace factor -{ -} diff --git a/vm/master.hpp b/vm/master.hpp index d942c1a3ac..97e9ed4a8b 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -69,9 +69,10 @@ namespace factor #include "bignumint.hpp" #include "bignum.hpp" #include "code_block.hpp" -#include "gc/zone.hpp" -#include "data_heap.hpp" +#include "zone.hpp" #include "write_barrier.hpp" +#include "old_space.hpp" +#include "data_heap.hpp" #include "data_gc.hpp" #include "debug.hpp" #include "strings.hpp" diff --git a/vm/old_space.hpp b/vm/old_space.hpp new file mode 100644 index 0000000000..598c1f4090 --- /dev/null +++ b/vm/old_space.hpp @@ -0,0 +1,62 @@ +namespace factor +{ + +struct old_space : zone { + card *allot_markers; + card *allot_markers_end; + + old_space(cell size_, cell start_) : zone(size_,start_) + { + cell cards_size = size_ >> card_bits; + allot_markers = new card[cards_size]; + allot_markers_end = allot_markers + cards_size; + } + + ~old_space() + { + delete[] allot_markers; + } + + card *addr_to_allot_marker(object *a) + { + return (card *)((((cell)a - start) >> card_bits) + (cell)allot_markers); + } + + /* we need to remember the first object allocated in the card */ + void record_allocation(object *obj) + { + card *ptr = addr_to_allot_marker(obj); + if(*ptr == invalid_allot_marker) + *ptr = ((cell)obj & addr_card_mask); + } + + cell card_offset(cell address) + { + return allot_markers[(address - start) >> card_bits]; + } + + object *allot(cell size) + { + if(here + size > end) return NULL; + + object *obj = zone::allot(size); + record_allocation(obj); + return obj; + } + + void clear_allot_markers() + { + memset(allot_markers,invalid_allot_marker,size >> card_bits); + } + + /* object *next_object_after(object *ptr) + { + cell size = untagged_object_size(ptr); + if((cell)ptr + size < end) + return (object *)((cell)ptr + size); + else + return NULL; + } */ +}; + +} diff --git a/vm/vm.cpp b/vm/vm.cpp index 15df6cc18a..50dc441086 100755 --- a/vm/vm.cpp +++ b/vm/vm.cpp @@ -4,6 +4,7 @@ namespace factor { factor_vm::factor_vm() : + nursery(0,0), profiling_p(false), secure_gc(false), gc_off(false), diff --git a/vm/vm.hpp b/vm/vm.hpp index 9836342fe2..02ab128969 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -53,9 +53,6 @@ struct factor_vm /* Code heap */ code_heap *code; - /* Where we store object start offsets in cards */ - cell allot_markers_offset; - /* Only set if we're performing a GC */ gc_state *current_gc; @@ -211,10 +208,9 @@ struct factor_vm //data_heap void init_card_decks(); data_heap *grow_data_heap(data_heap *data, cell requested_bytes); - void clear_cards(zone *gen); - void clear_decks(zone *gen); - void clear_allot_markers(zone *gen); - void reset_generation(zone *gen); + void clear_cards(old_space *gen); + void clear_decks(old_space *gen); + void reset_generation(old_space *gen); void set_data_heap(data_heap *data_); void init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_); cell untagged_object_size(object *pointer); @@ -243,11 +239,6 @@ struct factor_vm return ((cell)c - cards_offset) << card_bits; } - inline cell card_offset(card *c) - { - return *(c - (cell)data->cards + (cell)data->allot_markers); - } - inline card_deck *addr_to_deck(cell a) { return (card_deck *)(((cell)a >> deck_bits) + decks_offset); @@ -263,11 +254,6 @@ struct factor_vm return (card *)((((cell)d - decks_offset) << (deck_bits - card_bits)) + cards_offset); } - inline card *addr_to_allot_marker(object *a) - { - return (card *)(((cell)a >> card_bits) + allot_markers_offset); - } - /* the write barrier must be called any time we are potentially storing a pointer from an older generation to a younger one */ inline void write_barrier(object *obj) @@ -276,22 +262,14 @@ struct factor_vm *addr_to_deck((cell)obj) = card_mark_mask; } - /* we need to remember the first object allocated in the card */ - inline void allot_barrier(object *address) - { - card *ptr = addr_to_allot_marker(address); - if(*ptr == invalid_allot_marker) - *ptr = ((cell)address & addr_card_mask); - } - // data_gc template object *resolve_forwarding(object *untagged, Strategy &strategy); template void trace_handle(cell *handle, Strategy &strategy); template object *promote_object(object *pointer, Strategy &strategy); template void trace_slots(object *ptr, Strategy &strategy); - template void trace_card(card *ptr, cell here, Strategy &strategy); - template void trace_card_deck(card_deck *deck, cell here, card mask, card unmask, Strategy &strategy); - template void trace_cards(cell gen, zone *z, Strategy &strategy); + template void trace_card(card *ptr, old_space *gen, Strategy &strategy); + template void trace_card_deck(card_deck *deck, old_space *gen, card mask, card unmask, Strategy &strategy); + template void trace_cards(cell gen, old_space *z, Strategy &strategy); template void trace_stack_elements(segment *region, cell top, Strategy &strategy); template void trace_registered_locals(Strategy &strategy); template void trace_registered_bignums(Strategy &strategy); diff --git a/vm/write_barrier.cpp b/vm/write_barrier.cpp deleted file mode 100644 index 774f744a3f..0000000000 --- a/vm/write_barrier.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "master.hpp" - -using namespace factor; - diff --git a/vm/gc/zone.hpp b/vm/zone.hpp similarity index 100% rename from vm/gc/zone.hpp rename to vm/zone.hpp From 6939759f4620233e6f1312f6ac3935eadf9440ea Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 7 Oct 2009 15:48:09 -0500 Subject: [PATCH 26/63] vm: working on new object-oriented garbage collector --- Makefile | 5 ++ vm/aging_collector.cpp | 19 +++++ vm/aging_collector.hpp | 24 ++++++ vm/aging_space.hpp | 12 +++ vm/collector.hpp | 143 ++++++++++++++++++++++++++++++++ vm/copying_collector.hpp | 159 ++++++++++++++++++++++++++++++++++++ vm/data_gc.cpp | 46 +++++------ vm/data_gc.hpp | 4 +- vm/data_heap.cpp | 8 +- vm/data_heap.hpp | 8 +- vm/full_collector.cpp | 17 ++++ vm/full_collector.hpp | 23 ++++++ vm/master.hpp | 8 ++ vm/nursery_collector.cpp | 20 +++++ vm/nursery_collector.hpp | 20 +++++ vm/old_space.cpp | 54 ++++++++++++ vm/old_space.hpp | 53 ++---------- vm/tenured_space.hpp | 12 +++ vm/to_tenured_collector.cpp | 19 +++++ vm/to_tenured_collector.hpp | 21 +++++ vm/zone.hpp | 8 +- 21 files changed, 597 insertions(+), 86 deletions(-) create mode 100644 vm/aging_collector.cpp create mode 100644 vm/aging_collector.hpp create mode 100644 vm/aging_space.hpp create mode 100644 vm/collector.hpp create mode 100644 vm/copying_collector.hpp create mode 100644 vm/full_collector.cpp create mode 100644 vm/full_collector.hpp create mode 100644 vm/nursery_collector.cpp create mode 100644 vm/nursery_collector.hpp create mode 100644 vm/old_space.cpp create mode 100644 vm/tenured_space.hpp create mode 100644 vm/to_tenured_collector.cpp create mode 100644 vm/to_tenured_collector.hpp diff --git a/Makefile b/Makefile index 4c50787f2d..0b16233b63 100755 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ ifdef CONFIG endif DLL_OBJS = $(PLAF_DLL_OBJS) \ + vm/aging_collector.o \ vm/alien.o \ vm/arrays.o \ vm/bignum.o \ @@ -46,17 +47,21 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \ vm/dispatch.o \ vm/errors.o \ vm/factor.o \ + vm/full_collector.o \ vm/heap.o \ vm/image.o \ vm/inline_cache.o \ vm/io.o \ vm/jit.o \ vm/math.o \ + vm/nursery_collector.o \ + vm/old_space.o \ vm/primitives.o \ vm/profiler.o \ vm/quotations.o \ vm/run.o \ vm/strings.o \ + vm/to_tenured_collector.o \ vm/tuples.o \ vm/utilities.o \ vm/vm.o \ diff --git a/vm/aging_collector.cpp b/vm/aging_collector.cpp new file mode 100644 index 0000000000..918d5e322d --- /dev/null +++ b/vm/aging_collector.cpp @@ -0,0 +1,19 @@ +#include "master.hpp" + +namespace factor +{ + +aging_collector::aging_collector(factor_vm *myvm_) : + copying_collector + (myvm_,myvm_->data->aging,aging_policy(myvm_)) {} + +void aging_collector::go() +{ + trace_roots(); + trace_contexts(); + trace_cards(data->tenured); + trace_code_heap_roots(); + cheneys_algorithm(); +} + +} diff --git a/vm/aging_collector.hpp b/vm/aging_collector.hpp new file mode 100644 index 0000000000..71b8938710 --- /dev/null +++ b/vm/aging_collector.hpp @@ -0,0 +1,24 @@ +namespace factor +{ + +struct aging_policy { + factor_vm *myvm; + zone *aging, *tenured; + + aging_policy(factor_vm *myvm_) : + myvm(myvm_), + aging(myvm->data->aging), + tenured(myvm->data->tenured) {} + + bool should_copy_p(object *untagged) + { + return !(aging->contains_p(untagged) || tenured->contains_p(untagged)); + } +}; + +struct aging_collector : copying_collector { + aging_collector(factor_vm *myvm_); + void go(); +}; + +} diff --git a/vm/aging_space.hpp b/vm/aging_space.hpp new file mode 100644 index 0000000000..743363b10c --- /dev/null +++ b/vm/aging_space.hpp @@ -0,0 +1,12 @@ +namespace factor +{ + +struct aging_space : old_space { + aging_space(cell size, cell start) : old_space(size,start) {} + + bool is_nursery_p() { return false; } + bool is_aging_p() { return true; } + bool is_tenured_p() { return false; } +}; + +} diff --git a/vm/collector.hpp b/vm/collector.hpp new file mode 100644 index 0000000000..06134dd9b7 --- /dev/null +++ b/vm/collector.hpp @@ -0,0 +1,143 @@ +namespace factor +{ + +template struct collector { + factor_vm *myvm; + data_heap *data; + gc_state *current_gc; + TargetGeneration *target; + Policy policy; + + explicit collector(factor_vm *myvm_, TargetGeneration *target_, Policy policy_) : + myvm(myvm_), + data(myvm_->data), + current_gc(myvm_->current_gc), + target(target_), + policy(policy_) {} + + object *resolve_forwarding(object *untagged) + { + myvm->check_data_pointer(untagged); + + /* is there another forwarding pointer? */ + while(untagged->h.forwarding_pointer_p()) + untagged = untagged->h.forwarding_pointer(); + + /* we've found the destination */ + untagged->h.check_header(); + return untagged; + } + + void trace_handle(cell *handle) + { + cell pointer = *handle; + + if(immediate_p(pointer)) return; + + object *untagged = myvm->untag(pointer); + if(!policy.should_copy_p(untagged)) + return; + + object *forwarding = resolve_forwarding(untagged); + + if(forwarding == untagged) + untagged = promote_object(untagged); + else if(policy.should_copy_p(forwarding)) + untagged = promote_object(forwarding); + else + untagged = forwarding; + + *handle = RETAG(untagged,TAG(pointer)); + } + + void trace_slots(object *ptr) + { + cell *slot = (cell *)ptr; + cell *end = (cell *)((cell)ptr + myvm->binary_payload_start(ptr)); + + if(slot != end) + { + slot++; + for(; slot < end; slot++) trace_handle(slot); + } + } + + object *promote_object(object *untagged) + { + cell size = myvm->untagged_object_size(untagged); + object *newpointer = target->allot(size); + /* XXX not exception-safe */ + if(!newpointer) longjmp(current_gc->gc_unwind,1); + + memcpy(newpointer,untagged,size); + untagged->h.forward_to(newpointer); + + return newpointer; + } + + void trace_stack_elements(segment *region, cell *top) + { + for(cell *ptr = (cell *)region->start; ptr <= top; ptr++) + trace_handle(ptr); + } + + void trace_registered_locals() + { + std::vector::const_iterator iter = myvm->gc_locals.begin(); + std::vector::const_iterator end = myvm->gc_locals.end(); + + for(; iter < end; iter++) + trace_handle((cell *)(*iter)); + } + + void trace_registered_bignums() + { + std::vector::const_iterator iter = myvm->gc_bignums.begin(); + std::vector::const_iterator end = myvm->gc_bignums.end(); + + for(; iter < end; iter++) + { + cell *handle = (cell *)(*iter); + + if(*handle) + { + *handle |= BIGNUM_TYPE; + trace_handle(handle); + *handle &= ~BIGNUM_TYPE; + } + } + } + + /* Copy roots over at the start of GC, namely various constants, stacks, + the user environment and extra roots registered by local_roots.hpp */ + void trace_roots() + { + trace_handle(&myvm->T); + trace_handle(&myvm->bignum_zero); + trace_handle(&myvm->bignum_pos_one); + trace_handle(&myvm->bignum_neg_one); + + trace_registered_locals(); + trace_registered_bignums(); + + for(int i = 0; i < USER_ENV; i++) trace_handle(&myvm->userenv[i]); + } + + void trace_contexts() + { + context *stacks = myvm->stack_chain; + + while(stacks) + { + trace_stack_elements(stacks->datastack_region,(cell *)stacks->datastack); + trace_stack_elements(stacks->retainstack_region,(cell *)stacks->retainstack); + + trace_handle(&stacks->catchstack_save); + trace_handle(&stacks->current_callback_save); + + stacks = stacks->next; + } + } +}; + +} diff --git a/vm/copying_collector.hpp b/vm/copying_collector.hpp new file mode 100644 index 0000000000..bb17f2e70d --- /dev/null +++ b/vm/copying_collector.hpp @@ -0,0 +1,159 @@ +namespace factor +{ + +template +struct copying_collector : collector { + cell scan; + + explicit copying_collector(factor_vm *myvm_, TargetGeneration *target_, Policy policy_) : + collector(myvm_,target_,policy_), scan(target_->here) {} + + template void trace_objects_between(SourceGeneration *gen, cell scan, cell *end) + { + while(scan && scan < *end) + { + this->trace_slots((object *)scan); + scan = gen->next_object_after(this->myvm,scan); + } + } + + template void trace_card(SourceGeneration *gen, card *ptr) + { + cell card_start = this->myvm->card_to_addr(ptr); + cell card_scan = card_start + gen->card_offset(card_start); + cell card_end = this->myvm->card_to_addr(ptr + 1); + + trace_objects_between(gen,card_scan,&card_end); + + this->myvm->gc_stats.cards_scanned++; + } + + template void trace_card_deck(SourceGeneration *gen, card_deck *deck, card mask, card unmask) + { + card *first_card = this->myvm->deck_to_card(deck); + card *last_card = this->myvm->deck_to_card(deck + 1); + + u32 *quad_ptr; + u32 quad_mask = mask | (mask << 8) | (mask << 16) | (mask << 24); + + for(quad_ptr = (u32 *)first_card; quad_ptr < (u32 *)last_card; quad_ptr++) + { + if(*quad_ptr & quad_mask) + { + card *ptr = (card *)quad_ptr; + + for(int card = 0; card < 4; card++) + { + if(ptr[card] & mask) + { + trace_card(gen,&ptr[card]); + ptr[card] &= ~unmask; + } + } + } + } + + this->myvm->gc_stats.decks_scanned++; + } + + template void trace_cards(SourceGeneration *gen) + { + u64 start = current_micros(); + + card_deck *first_deck = this->myvm->addr_to_deck(gen->start); + card_deck *last_deck = this->myvm->addr_to_deck(gen->end); + + card mask, unmask; + + /* if we are collecting the nursery, we care about old->nursery pointers + but not old->aging pointers */ + if(this->current_gc->collecting_nursery_p()) + { + mask = card_points_to_nursery; + + /* after the collection, no old->nursery pointers remain + anywhere, but old->aging pointers might remain in tenured + space */ + if(gen->is_tenured_p()) + unmask = card_points_to_nursery; + /* after the collection, all cards in aging space can be + cleared */ + else if(gen->is_aging_p()) + unmask = card_mark_mask; + else + { + critical_error("bug in trace_gen_cards",0); + return; + } + } + /* if we are collecting aging space into tenured space, we care about + all old->nursery and old->aging pointers. no old->aging pointers can + remain */ + else if(this->current_gc->collecting_aging_p()) + { + if(this->current_gc->collecting_aging_again) + { + mask = card_points_to_aging; + unmask = card_mark_mask; + } + /* after we collect aging space into the aging semispace, no + old->nursery pointers remain but tenured space might still have + pointers to aging space. */ + else + { + mask = card_points_to_aging; + unmask = card_points_to_nursery; + } + } + else + { + critical_error("bug in trace_gen_cards",0); + return; + } + + for(card_deck *ptr = first_deck; ptr < last_deck; ptr++) + { + if(*ptr & mask) + { + trace_card_deck(gen,ptr,mask,unmask); + *ptr &= ~unmask; + } + } + + this->myvm->gc_stats.card_scan_time += (current_micros() - start); + } + + /* Trace all literals referenced from a code block. Only for aging and nursery collections */ + void trace_literal_references(code_block *compiled) + { + this->trace_handle(&compiled->owner); + this->trace_handle(&compiled->literals); + this->trace_handle(&compiled->relocation); + } + + /* Trace literals referenced from all code blocks. Only for aging and nursery collections */ + void trace_code_heap_roots() + { + if(this->current_gc->collecting_gen >= this->myvm->code->youngest_referenced_generation) + { + unordered_map &remembered_set = this->myvm->code->remembered_set; + unordered_map::const_iterator iter = remembered_set.begin(); + unordered_map::const_iterator end = remembered_set.end(); + + for(; iter != end; iter++) + { + if(this->current_gc->collecting_gen >= iter->second) + trace_literal_references(iter->first); + } + + this->myvm->gc_stats.code_heap_scans++; + } + } + + void cheneys_algorithm() + { + trace_objects_between(this->target,scan,&this->target->here); + } +}; + +} diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index dfe5ef3365..7e3aa95e11 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -399,48 +399,48 @@ void factor_vm::update_dirty_code_blocks() } template -copying_collector::copying_collector(factor_vm *myvm_, old_space *target_) +cheney_collector::cheney_collector(factor_vm *myvm_, old_space *target_) : myvm(myvm_), current_gc(myvm_->current_gc), target(target_) { scan = target->here; } -template Strategy ©ing_collector::strategy() +template Strategy &cheney_collector::strategy() { return static_cast(*this); } -template object *copying_collector::allot(cell size) +template object *cheney_collector::allot(cell size) { return target->allot(size); } -template object *copying_collector::copy_object(object *untagged) +template object *cheney_collector::copy_object(object *untagged) { return myvm->promote_object(untagged,strategy()); } -template bool copying_collector::should_copy_p(object *pointer) +template bool cheney_collector::should_copy_p(object *pointer) { return strategy().should_copy_p(pointer); } -template cell copying_collector::trace_next(cell scan) +template cell cheney_collector::trace_next(cell scan) { object *obj = (object *)scan; myvm->trace_slots(obj,strategy()); return scan + myvm->untagged_object_size(obj); } -template void copying_collector::go() +template void cheney_collector::go() { strategy().copy_reachable_objects(scan,&target->here); } -struct nursery_collector : copying_collector +struct nursery_strategy : cheney_collector { - explicit nursery_collector(factor_vm *myvm_, old_space *target_) : - copying_collector(myvm_,target_) {} + explicit nursery_strategy(factor_vm *myvm_, old_space *target_) : + cheney_collector(myvm_,target_) {} bool should_copy_p(object *untagged) { @@ -453,12 +453,12 @@ struct nursery_collector : copying_collector } }; -struct aging_collector : copying_collector +struct aging_strategy : cheney_collector { zone *tenured; - explicit aging_collector(factor_vm *myvm_, old_space *target_) : - copying_collector(myvm_,target_), + explicit aging_strategy(factor_vm *myvm_, old_space *target_) : + cheney_collector(myvm_,target_), tenured(myvm->data->tenured) {} bool should_copy_p(object *untagged) @@ -475,10 +475,10 @@ struct aging_collector : copying_collector } }; -struct aging_again_collector : copying_collector +struct aging_agian_strategy : cheney_collector { - explicit aging_again_collector(factor_vm *myvm_, old_space *target_) : - copying_collector(myvm_,target_) {} + explicit aging_agian_strategy(factor_vm *myvm_, old_space *target_) : + cheney_collector(myvm_,target_) {} bool should_copy_p(object *untagged) { @@ -491,10 +491,10 @@ struct aging_again_collector : copying_collector } }; -struct tenured_collector : copying_collector +struct tenured_strategy : cheney_collector { - explicit tenured_collector(factor_vm *myvm_, old_space *target_) : - copying_collector(myvm_,target_) {} + explicit tenured_strategy(factor_vm *myvm_, old_space *target_) : + cheney_collector(myvm_,target_) {} bool should_copy_p(object *untagged) { @@ -513,7 +513,7 @@ struct tenured_collector : copying_collector void factor_vm::collect_nursery() { - nursery_collector collector(this,data->aging); + nursery_strategy collector(this,data->aging); trace_roots(collector); trace_contexts(collector); @@ -531,7 +531,7 @@ void factor_vm::collect_aging() std::swap(data->aging,data->aging_semispace); reset_generation(data->aging); - aging_collector collector(this,data->aging); + aging_strategy collector(this,data->aging); trace_roots(collector); trace_contexts(collector); @@ -545,7 +545,7 @@ void factor_vm::collect_aging() void factor_vm::collect_aging_again() { - aging_again_collector collector(this,data->tenured); + aging_agian_strategy collector(this,data->tenured); trace_roots(collector); trace_contexts(collector); @@ -571,7 +571,7 @@ void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_) reset_generation(data->tenured); } - tenured_collector collector(this,data->tenured); + tenured_strategy collector(this,data->tenured); trace_roots(collector); if(trace_contexts_) trace_contexts(collector); diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index 9032f6696d..d9bed8e785 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -63,13 +63,13 @@ struct gc_state { } }; -template struct copying_collector { +template struct cheney_collector { factor_vm *myvm; gc_state *current_gc; old_space *target; cell scan; - explicit copying_collector(factor_vm *myvm_, old_space *target); + explicit cheney_collector(factor_vm *myvm_, old_space *target); Strategy &strategy(); object *allot(cell size); cell trace_next(cell scan); diff --git a/vm/data_heap.cpp b/vm/data_heap.cpp index 7e358cb2f9..9b0710ae52 100755 --- a/vm/data_heap.cpp +++ b/vm/data_heap.cpp @@ -37,11 +37,11 @@ data_heap::data_heap(factor_vm *myvm, cell young_size_, cell aging_size_, cell t cell start = align(seg->start,deck_size); - tenured = new old_space(tenured_size,start); - tenured_semispace = new old_space(tenured_size,tenured->end); + tenured = new tenured_space(tenured_size,start); + tenured_semispace = new tenured_space(tenured_size,tenured->end); - aging = new old_space(aging_size,tenured_semispace->end); - aging_semispace = new old_space(aging_size,aging->end); + aging = new aging_space(aging_size,tenured_semispace->end); + aging_semispace = new aging_space(aging_size,aging->end); nursery = new zone(young_size,aging_semispace->end); diff --git a/vm/data_heap.hpp b/vm/data_heap.hpp index 3f620e3d42..36c75e23b9 100755 --- a/vm/data_heap.hpp +++ b/vm/data_heap.hpp @@ -9,10 +9,10 @@ struct data_heap { segment *seg; zone *nursery; - old_space *aging; - old_space *aging_semispace; - old_space *tenured; - old_space *tenured_semispace; + aging_space *aging; + aging_space *aging_semispace; + tenured_space *tenured; + tenured_space *tenured_semispace; char *cards; char *cards_end; diff --git a/vm/full_collector.cpp b/vm/full_collector.cpp new file mode 100644 index 0000000000..24ebe3c5e8 --- /dev/null +++ b/vm/full_collector.cpp @@ -0,0 +1,17 @@ +#include "master.hpp" + +namespace factor +{ + +full_collector::full_collector(factor_vm *myvm_, bool trace_contexts_p_) : + copying_collector(myvm_,myvm_->data->tenured,full_policy(myvm_)), + trace_contexts_p(trace_contexts_p_) {} + +void full_collector::go() +{ + trace_roots(); + if(trace_contexts_p) trace_contexts(); + cheneys_algorithm(); +} + +} diff --git a/vm/full_collector.hpp b/vm/full_collector.hpp new file mode 100644 index 0000000000..71ac569772 --- /dev/null +++ b/vm/full_collector.hpp @@ -0,0 +1,23 @@ +namespace factor +{ + +struct full_policy { + factor_vm *myvm; + zone *tenured; + + full_policy(factor_vm *myvm_) : myvm(myvm_), tenured(myvm->data->tenured) {} + + bool should_copy_p(object *untagged) + { + return !tenured->contains_p(untagged); + } +}; + +struct full_collector : copying_collector { + bool trace_contexts_p; + + full_collector(factor_vm *myvm_, bool trace_contexts_p_); + void go(); +}; + +} diff --git a/vm/master.hpp b/vm/master.hpp index 97e9ed4a8b..0e8a03fff6 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -72,6 +72,8 @@ namespace factor #include "zone.hpp" #include "write_barrier.hpp" #include "old_space.hpp" +#include "aging_space.hpp" +#include "tenured_space.hpp" #include "data_heap.hpp" #include "data_gc.hpp" #include "debug.hpp" @@ -87,6 +89,12 @@ namespace factor #include "vm.hpp" #include "tagged.hpp" #include "local_roots.hpp" +#include "collector.hpp" +#include "copying_collector.hpp" +#include "nursery_collector.hpp" +#include "aging_collector.hpp" +#include "to_tenured_collector.hpp" +#include "full_collector.hpp" #include "callstack.hpp" #include "generic_arrays.hpp" #include "arrays.hpp" diff --git a/vm/nursery_collector.cpp b/vm/nursery_collector.cpp new file mode 100644 index 0000000000..302f958562 --- /dev/null +++ b/vm/nursery_collector.cpp @@ -0,0 +1,20 @@ +#include "master.hpp" + +namespace factor +{ + +nursery_collector::nursery_collector(factor_vm *myvm_) : + copying_collector + (myvm_,myvm_->data->aging,nursery_policy(myvm_)) {} + +void nursery_collector::go() +{ + trace_roots(); + trace_contexts(); + trace_cards(data->tenured); + trace_cards(data->aging); + trace_code_heap_roots(); + cheneys_algorithm(); +} + +} diff --git a/vm/nursery_collector.hpp b/vm/nursery_collector.hpp new file mode 100644 index 0000000000..1cfe063187 --- /dev/null +++ b/vm/nursery_collector.hpp @@ -0,0 +1,20 @@ +namespace factor +{ + +struct nursery_policy { + factor_vm *myvm; + + nursery_policy(factor_vm *myvm_) : myvm(myvm_) {} + + bool should_copy_p(object *untagged) + { + return myvm->nursery.contains_p(untagged); + } +}; + +struct nursery_collector : copying_collector { + nursery_collector(factor_vm *myvm_); + void go(); +}; + +} diff --git a/vm/old_space.cpp b/vm/old_space.cpp new file mode 100644 index 0000000000..572f1edc14 --- /dev/null +++ b/vm/old_space.cpp @@ -0,0 +1,54 @@ +#include "master.hpp" + +namespace factor +{ + +old_space::old_space(cell size_, cell start_) : zone(size_,start_) +{ + cell cards_size = size_ >> card_bits; + allot_markers = new card[cards_size]; + allot_markers_end = allot_markers + cards_size; +} + +old_space::~old_space() +{ + delete[] allot_markers; +} + +card *old_space::addr_to_allot_marker(object *a) +{ + return (card *)((((cell)a - start) >> card_bits) + (cell)allot_markers); +} + +/* we need to remember the first object allocated in the card */ +void old_space::record_allocation(object *obj) +{ + card *ptr = addr_to_allot_marker(obj); + if(*ptr == invalid_allot_marker) + *ptr = ((cell)obj & addr_card_mask); +} + +object *old_space::allot(cell size) +{ + if(here + size > end) return NULL; + + object *obj = zone::allot(size); + record_allocation(obj); + return obj; +} + +void old_space::clear_allot_markers() +{ + memset(allot_markers,invalid_allot_marker,size >> card_bits); +} + +cell old_space::next_object_after(factor_vm *myvm, cell scan) +{ + cell size = myvm->untagged_object_size((object *)scan); + if(scan + size < end) + return scan + size; + else + return NULL; +} + +} diff --git a/vm/old_space.hpp b/vm/old_space.hpp index 598c1f4090..3f70403400 100644 --- a/vm/old_space.hpp +++ b/vm/old_space.hpp @@ -5,58 +5,19 @@ struct old_space : zone { card *allot_markers; card *allot_markers_end; - old_space(cell size_, cell start_) : zone(size_,start_) - { - cell cards_size = size_ >> card_bits; - allot_markers = new card[cards_size]; - allot_markers_end = allot_markers + cards_size; - } - - ~old_space() - { - delete[] allot_markers; - } - - card *addr_to_allot_marker(object *a) - { - return (card *)((((cell)a - start) >> card_bits) + (cell)allot_markers); - } - - /* we need to remember the first object allocated in the card */ - void record_allocation(object *obj) - { - card *ptr = addr_to_allot_marker(obj); - if(*ptr == invalid_allot_marker) - *ptr = ((cell)obj & addr_card_mask); - } + old_space(cell size_, cell start_); + ~old_space(); cell card_offset(cell address) { return allot_markers[(address - start) >> card_bits]; } - object *allot(cell size) - { - if(here + size > end) return NULL; - - object *obj = zone::allot(size); - record_allocation(obj); - return obj; - } - - void clear_allot_markers() - { - memset(allot_markers,invalid_allot_marker,size >> card_bits); - } - - /* object *next_object_after(object *ptr) - { - cell size = untagged_object_size(ptr); - if((cell)ptr + size < end) - return (object *)((cell)ptr + size); - else - return NULL; - } */ + card *addr_to_allot_marker(object *a); + void record_allocation(object *obj); + object *allot(cell size); + void clear_allot_markers(); + cell next_object_after(factor_vm *myvm, cell scan); }; } diff --git a/vm/tenured_space.hpp b/vm/tenured_space.hpp new file mode 100644 index 0000000000..a05b272fb6 --- /dev/null +++ b/vm/tenured_space.hpp @@ -0,0 +1,12 @@ +namespace factor +{ + +struct tenured_space : old_space { + tenured_space(cell size, cell start) : old_space(size,start) {} + + bool is_nursery_p() { return false; } + bool is_aging_p() { return false; } + bool is_tenured_p() { return true; } +}; + +} diff --git a/vm/to_tenured_collector.cpp b/vm/to_tenured_collector.cpp new file mode 100644 index 0000000000..2693e35a2f --- /dev/null +++ b/vm/to_tenured_collector.cpp @@ -0,0 +1,19 @@ +#include "master.hpp" + +namespace factor +{ + +to_tenured_collector::to_tenured_collector(factor_vm *myvm_) : + copying_collector + (myvm_,myvm_->data->tenured,to_tenured_policy(myvm_)) {} + +void to_tenured_collector::go() +{ + trace_roots(); + trace_contexts(); + trace_cards(data->tenured); + trace_code_heap_roots(); + cheneys_algorithm(); +} + +} diff --git a/vm/to_tenured_collector.hpp b/vm/to_tenured_collector.hpp new file mode 100644 index 0000000000..55561252bc --- /dev/null +++ b/vm/to_tenured_collector.hpp @@ -0,0 +1,21 @@ +namespace factor +{ + +struct to_tenured_policy { + factor_vm *myvm; + zone *tenured; + + to_tenured_policy(factor_vm *myvm_) : myvm(myvm_), tenured(myvm->data->tenured) {} + + bool should_copy_p(object *untagged) + { + return !tenured->contains_p(untagged); + } +}; + +struct to_tenured_collector : copying_collector { + to_tenured_collector(factor_vm *myvm_); + void go(); +}; + +} diff --git a/vm/zone.hpp b/vm/zone.hpp index a05afd45c6..25859fe500 100644 --- a/vm/zone.hpp +++ b/vm/zone.hpp @@ -9,13 +9,7 @@ struct zone { cell size; cell end; - cell init_zone(cell size_, cell start_) - { - size = size_; - start = here = start_; - end = start_ + size_; - return end; - } + zone(cell size_, cell start_) : start(start_), here(0), size(size_), end(start_ + size_) {} inline bool contains_p(object *pointer) { From 1a2c137e412df8bdc7d48d15dc54e4378cd8575d Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Wed, 7 Oct 2009 21:35:12 -0500 Subject: [PATCH 27/63] Refactoring bitfields to not use number tower --- basis/classes/struct/struct-tests.factor | 8 +++ basis/classes/struct/struct.factor | 91 +++++++++++------------- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/basis/classes/struct/struct-tests.factor b/basis/classes/struct/struct-tests.factor index b59fc4577c..58ab2df80b 100755 --- a/basis/classes/struct/struct-tests.factor +++ b/basis/classes/struct/struct-tests.factor @@ -357,3 +357,11 @@ STRUCT: bit-field-test { a uint bits: 12 } { b int bits: 2 } { c char } ; + +[ S{ bit-field-test f 0 0 0 } ] [ bit-field-test ] unit-test +[ S{ bit-field-test f 1 -2 3 } ] [ bit-field-test 1 >>a 2 >>b 3 >>c ] unit-test +[ 4095 ] [ bit-field-test 8191 >>a a>> ] unit-test +[ 1 ] [ bit-field-test 1 >>b b>> ] unit-test +[ -2 ] [ bit-field-test 2 >>b b>> ] unit-test +[ 1 ] [ bit-field-test 257 >>c c>> ] unit-test +[ 3 ] [ bit-field-test heap-size ] unit-test diff --git a/basis/classes/struct/struct.factor b/basis/classes/struct/struct.factor index f8bdac530e..df0e07c964 100755 --- a/basis/classes/struct/struct.factor +++ b/basis/classes/struct/struct.factor @@ -12,23 +12,6 @@ IN: classes.struct SPECIALIZED-ARRAY: uchar - bits - -M: bits heap-size size>> 8 / ; - -M: bits c-type-align drop 1/8 ; - -: align ( m w -- n ) - ! Really, you could write 'align' correctly - ! for any real w; this is just a hack - ! that only works here - dup integer? [ [ ceiling ] dip math:align ] [ drop ] if ; - -PRIVATE> - ERROR: struct-must-have-slots ; M: struct-must-have-slots summary @@ -40,6 +23,10 @@ TUPLE: struct TUPLE: struct-slot-spec < slot-spec type ; +! For a struct-bit-slot-spec, offset is in bits, not bytes +TUPLE: struct-bit-slot-spec < struct-slot-spec + bits signed? ; + PREDICATE: struct-class < tuple-class superclass \ struct eq? ; @@ -102,19 +89,15 @@ MACRO: ( class -- quot: ( ... -- struct ) ) : pad-struct-slots ( values class -- values' class ) [ struct-slots [ initial>> ] map over length tail append ] keep ; -: read-normal ( slot -- quot ) - [ type>> c-type-getter-boxer ] - [ offset>> [ >c-ptr ] swap suffix ] bi prepend ; - : bits@ ( slot -- beginning end ) - [ offset>> 8 * ] [ type>> size>> ] bi dupd + ; + [ offset>> ] [ bits>> ] bi dupd + ; QUALIFIED: math.bits : bytes>bits ( byte-array -- bit-array ) [ 8 math.bits: ] { } map-as ?{ } join ; -: (read-bits) ( beginning end byte-array -- n ) +: read-bits ( beginning end byte-array -- n ) ! This is absurdly inefficient bytes>bits subseq bit-array>integer ; @@ -123,35 +106,34 @@ QUALIFIED: math.bits ! http://guru.multimedia.cx/fast-sign-extension/ 1 - -1 swap shift [ + ] keep bitxor ; inline -: read-bits ( slot -- quot ) - [ bits@ ] [ type>> signed?>> ] [ type>> size>> ] tri '[ - [ _ _ ] dip (underlying)>> (read-bits) +GENERIC: (reader-quot) ( slot -- quot ) + +M: struct-slot-spec (reader-quot) + [ type>> c-type-getter-boxer ] + [ offset>> [ >c-ptr ] swap suffix ] bi prepend ; + +M: struct-bit-slot-spec (reader-quot) + [ bits@ ] [ signed?>> ] [ bits>> ] tri '[ + [ _ _ ] dip (underlying)>> read-bits _ [ _ sign-extend ] when ] ; -: (reader-quot) ( slot -- quot ) - dup type>> bits? [ read-bits ] [ read-normal ] if ; +GENERIC: (writer-quot) ( slot -- quot ) -: write-normal ( slot -- quot ) +M: struct-slot-spec (writer-quot) [ type>> c-setter ] [ offset>> [ >c-ptr ] swap suffix ] bi prepend ; -: overwrite ( donor victim -- ) - 0 swap copy ; - : (write-bits) ( value offset end byte-array -- ) ! This is absurdly inefficient [ [ [ swap - math.bits: ] 2keep ] [ bytes>bits ] bi* replace-slice ?{ } like underlying>> - ] keep overwrite ; + ] keep 0 swap copy ; -: write-bits ( slot -- quot ) +M: struct-bit-slot-spec (writer-quot) ( slot -- quot ) bits@ '[ [ _ _ ] dip (underlying)>> (write-bits) ] ; -: (writer-quot) ( slot -- quot ) - dup type>> bits? [ write-bits ] [ write-normal ] if ; - : (boxer-quot) ( class -- quot ) '[ _ memory>struct ] ; @@ -246,19 +228,23 @@ M: struct-c-type c-struct? drop t ; class (unboxer-quot) >>unboxer-quot class (boxer-quot) >>boxer-quot ; -: align-offset ( offset class -- offset' ) - c-type-align align ; +GENERIC: align-offset ( offset class -- offset' ) + +M: struct-slot-spec align-offset + [ type>> c-type-align 8 * align ] keep + [ [ 8 /i ] dip (>>offset) ] [ type>> heap-size 8 * + ] 2bi ; + +M: struct-bit-slot-spec align-offset + [ (>>offset) ] [ bits>> + ] 2bi ; : struct-offsets ( slots -- size ) - 0 [ - [ type>> align-offset ] keep - [ (>>offset) ] [ type>> heap-size + ] 2bi - ] reduce ; + 0 [ align-offset ] reduce 8 align 8 /i ; : union-struct-offsets ( slots -- size ) 1 [ 0 >>offset type>> heap-size max ] reduce ; : struct-align ( slots -- align ) + [ struct-bit-slot-spec? not ] filter 1 [ type>> c-type-align max ] reduce ; PRIVATE> @@ -339,12 +325,19 @@ SYMBOL: bits: ERROR: bad-type-for-bits type ; -: set-bits ( slot-spec n -- slot-spec ) - over type>> { - { int [ t ] } - { uint [ f ] } - [ bad-type-for-bits ] - } case >>type ; +:: set-bits ( slot-spec n -- slot-spec ) + struct-bit-slot-spec new + n >>bits + slot-spec type>> { + { int [ t ] } + { uint [ f ] } + [ bad-type-for-bits ] + } case >>signed? + slot-spec name>> >>name + slot-spec class>> >>class + slot-spec type>> >>type + slot-spec read-only>> >>read-only + slot-spec initial>> >>initial ; : peel-off-struct-attributes ( slot-spec array -- slot-spec array ) dup empty? [ From 4e1aa8f638505028801f33dbef00b00377f785cf Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Wed, 7 Oct 2009 21:42:15 -0500 Subject: [PATCH 28/63] Modifying the struct prettyprinter to display bits --- basis/classes/struct/prettyprint/prettyprint.factor | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/basis/classes/struct/prettyprint/prettyprint.factor b/basis/classes/struct/prettyprint/prettyprint.factor index 43d24e5716..b7b51432dd 100644 --- a/basis/classes/struct/prettyprint/prettyprint.factor +++ b/basis/classes/struct/prettyprint/prettyprint.factor @@ -23,6 +23,11 @@ IN: classes.struct.prettyprint [ type>> pprint-c-type ] [ read-only>> [ \ read-only pprint-word ] when ] [ initial>> [ \ initial: pprint-word pprint* ] when* ] + [ + dup struct-bit-slot-spec? + [ \ bits: pprint-word bits>> pprint* ] + [ drop ] if + ] } cleave block> \ } pprint-word block> ; From 3179dacb3e4ad507b4746ac8a748f6de334513cc Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Wed, 7 Oct 2009 23:51:18 -0500 Subject: [PATCH 29/63] Making struct bitfield readers fast --- .../struct/bit-accessors/bit-accessors.factor | 29 ++++++++++++++++ basis/classes/struct/struct.factor | 34 +++++++++---------- 2 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 basis/classes/struct/bit-accessors/bit-accessors.factor diff --git a/basis/classes/struct/bit-accessors/bit-accessors.factor b/basis/classes/struct/bit-accessors/bit-accessors.factor new file mode 100644 index 0000000000..9d625beab3 --- /dev/null +++ b/basis/classes/struct/bit-accessors/bit-accessors.factor @@ -0,0 +1,29 @@ +! Copyright (C) 2009 Daniel Ehrenberg +! See http://factorcode.org/license.txt for BSD license. +USING: kernel sequences math fry locals math.order alien.accessors ; +IN: classes.struct.bit-accessors + +! Bitfield accessors are little-endian on all platforms +! Why not? It's platform-dependent in C + +: ones-between ( start end -- n ) + [ 2^ 1 - ] bi@ swap bitnot bitand ; + +:: read-bits ( offset bits -- quot: ( byte-array -- n ) shift-amount offset' bits' ) + offset 8 /mod :> start-bit :> i + start-bit bits + 8 min :> end-bit + start-bit end-bit ones-between :> mask + end-bit start-bit - :> used-bits + + ! The code generated for this isn't optimal + ! To improve the code, algebraic simplifications should + ! have interval information available + [ i alien-unsigned-1 mask bitand start-bit neg shift ] + used-bits + i 1 + 8 * + bits used-bits - ; + +: bit-reader ( offset bits -- quot: ( alien -- n ) ) + read-bits dup zero? [ 3drop ] [ + bit-reader swap '[ _ _ bi _ shift bitor ] + ] if ; diff --git a/basis/classes/struct/struct.factor b/basis/classes/struct/struct.factor index df0e07c964..6593e8350d 100755 --- a/basis/classes/struct/struct.factor +++ b/basis/classes/struct/struct.factor @@ -6,7 +6,8 @@ combinators.smart cpu.architecture definitions functors.backend fry generalizations generic.parser kernel kernel.private lexer libc locals macros make math math.order parser quotations sequences slots slots.private specialized-arrays vectors words -summary namespaces assocs vocabs.parser math.functions bit-arrays ; +summary namespaces assocs vocabs.parser math.functions +classes.struct.bit-accessors bit-arrays ; QUALIFIED: math IN: classes.struct @@ -89,23 +90,14 @@ MACRO: ( class -- quot: ( ... -- struct ) ) : pad-struct-slots ( values class -- values' class ) [ struct-slots [ initial>> ] map over length tail append ] keep ; -: bits@ ( slot -- beginning end ) - [ offset>> ] [ bits>> ] bi dupd + ; - -QUALIFIED: math.bits - -: bytes>bits ( byte-array -- bit-array ) - [ 8 math.bits: ] { } map-as ?{ } join ; - -: read-bits ( beginning end byte-array -- n ) - ! This is absurdly inefficient - bytes>bits subseq bit-array>integer ; - : sign-extend ( n bits -- n' ) ! formula from: ! http://guru.multimedia.cx/fast-sign-extension/ 1 - -1 swap shift [ + ] keep bitxor ; inline +: sign-extender ( signed? bits -- quot ) + '[ _ [ _ sign-extend ] when ] ; + GENERIC: (reader-quot) ( slot -- quot ) M: struct-slot-spec (reader-quot) @@ -113,10 +105,10 @@ M: struct-slot-spec (reader-quot) [ offset>> [ >c-ptr ] swap suffix ] bi prepend ; M: struct-bit-slot-spec (reader-quot) - [ bits@ ] [ signed?>> ] [ bits>> ] tri '[ - [ _ _ ] dip (underlying)>> read-bits - _ [ _ sign-extend ] when - ] ; + [ [ offset>> ] [ bits>> ] bi bit-reader ] + [ [ signed?>> ] [ bits>> ] bi sign-extender ] + bi compose + [ >c-ptr ] prepose ; GENERIC: (writer-quot) ( slot -- quot ) @@ -124,6 +116,11 @@ M: struct-slot-spec (writer-quot) [ type>> c-setter ] [ offset>> [ >c-ptr ] swap suffix ] bi prepend ; +QUALIFIED: math.bits + +: bytes>bits ( byte-array -- bit-array ) + [ 8 math.bits: ] { } map-as ?{ } join ; + : (write-bits) ( value offset end byte-array -- ) ! This is absurdly inefficient [ @@ -131,6 +128,9 @@ M: struct-slot-spec (writer-quot) replace-slice ?{ } like underlying>> ] keep 0 swap copy ; +: bits@ ( slot -- beginning end ) + [ offset>> ] [ bits>> ] bi dupd + ; + M: struct-bit-slot-spec (writer-quot) ( slot -- quot ) bits@ '[ [ _ _ ] dip (underlying)>> (write-bits) ] ; From db29d60e8e22a6e11de1a1179701e0383d905f91 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 8 Oct 2009 00:23:29 -0500 Subject: [PATCH 30/63] vm: add code block marking to full_collector.cpp --- vm/full_collector.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++ vm/full_collector.hpp | 4 +++ 2 files changed, 75 insertions(+) diff --git a/vm/full_collector.cpp b/vm/full_collector.cpp index 24ebe3c5e8..bead2f7338 100644 --- a/vm/full_collector.cpp +++ b/vm/full_collector.cpp @@ -7,6 +7,77 @@ full_collector::full_collector(factor_vm *myvm_, bool trace_contexts_p_) : copying_collector(myvm_,myvm_->data->tenured,full_policy(myvm_)), trace_contexts_p(trace_contexts_p_) {} +struct stack_frame_marker { + factor_vm *myvm; + full_collector *collector; + + explicit stack_frame_marker(full_collector *collector_) : + myvm(collector_->myvm), collector(collector_) {} + + void operator()(stack_frame *frame) + { + collector->mark_code_block(myvm->frame_code(frame)); + } +}; + +/* Mark code blocks executing in currently active stack frames. */ +void full_collector::mark_active_blocks(context *stacks) +{ + cell top = (cell)stacks->callstack_top; + cell bottom = (cell)stacks->callstack_bottom; + + stack_frame_marker marker(this); + myvm->iterate_callstack(top,bottom,marker); +} + +void full_collector::mark_object_code_block(object *object) +{ + switch(object->h.hi_tag()) + { + case WORD_TYPE: + { + word *w = (word *)object; + if(w->code) + mark_code_block(w->code); + if(w->profiling) + mark_code_block(w->profiling); + break; + } + case QUOTATION_TYPE: + { + quotation *q = (quotation *)object; + if(q->code) + mark_code_block(q->code); + break; + } + case CALLSTACK_TYPE: + { + callstack *stack = (callstack *)object; + stack_frame_marker marker(this); + myvm->iterate_callstack_object(stack,marker); + break; + } + } +} + +/* Trace all literals referenced from a code block. Only for aging and nursery collections */ +void full_collector::trace_literal_references(code_block *compiled) +{ + this->trace_handle(&compiled->owner); + this->trace_handle(&compiled->literals); + this->trace_handle(&compiled->relocation); +} + +/* Mark all literals referenced from a word XT. Only for tenured +collections */ +void full_collector::mark_code_block(code_block *compiled) +{ + myvm->check_code_address((cell)compiled); + + this->myvm->code->mark_block(compiled); + trace_literal_references(compiled); +} + void full_collector::go() { trace_roots(); diff --git a/vm/full_collector.hpp b/vm/full_collector.hpp index 71ac569772..d5c47416fa 100644 --- a/vm/full_collector.hpp +++ b/vm/full_collector.hpp @@ -17,6 +17,10 @@ struct full_collector : copying_collector { bool trace_contexts_p; full_collector(factor_vm *myvm_, bool trace_contexts_p_); + void mark_active_blocks(context *stacks); + void mark_object_code_block(object *object); + void trace_literal_references(code_block *compiled); + void mark_code_block(code_block *compiled); void go(); }; From eb31589092b7c01eb88667b1d59885ecfcc050fd Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 8 Oct 2009 00:59:15 -0500 Subject: [PATCH 31/63] Adding identity to propagation to remove some redundant bitands --- .../tree/propagation/propagation-tests.factor | 3 +++ .../propagation/transforms/transforms.factor | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/basis/compiler/tree/propagation/propagation-tests.factor b/basis/compiler/tree/propagation/propagation-tests.factor index 92964654bf..c1b6691542 100644 --- a/basis/compiler/tree/propagation/propagation-tests.factor +++ b/basis/compiler/tree/propagation/propagation-tests.factor @@ -899,3 +899,6 @@ M: tuple-with-read-only-slot clone ! We want this to inline [ t ] [ [ void* ] { } inlined? ] unit-test [ V{ void*-array } ] [ [ void* ] final-classes ] unit-test + +[ t ] [ [ alien-unsigned-1 255 bitand ] { bitand fixnum-bitand } inlined? ] unit-test +[ t ] [ [ alien-unsigned-1 255 swap bitand ] { bitand fixnum-bitand } inlined? ] unit-test diff --git a/basis/compiler/tree/propagation/transforms/transforms.factor b/basis/compiler/tree/propagation/transforms/transforms.factor index 8aa6a821d8..08ac306248 100644 --- a/basis/compiler/tree/propagation/transforms/transforms.factor +++ b/basis/compiler/tree/propagation/transforms/transforms.factor @@ -45,6 +45,14 @@ IN: compiler.tree.propagation.transforms : simplify-bitand? ( value -- ? ) value-info literal>> positive-fixnum? ; +: redundant-bitand? ( var 111... -- ? ) + [ value-info ] bi@ { [ + nip literal>> + { [ positive-fixnum? ] [ dup 1 + bitand zero? ] } 1&& + ] [ + [ interval>> ] [ literal>> ] bi* 0 swap [a,b] interval-subset? + ] } 2&& ; + { bitand-integer-integer bitand-integer-fixnum @@ -53,6 +61,14 @@ IN: compiler.tree.propagation.transforms } [ [ { + { + [ dup in-d>> first2 redundant-bitand? ] + [ drop [ drop ] ] + } + { + [ dup in-d>> first2 swap redundant-bitand? ] + [ drop [ nip ] ] + } { [ dup in-d>> first simplify-bitand? ] [ drop [ >fixnum fixnum-bitand ] ] From 2db25b937eee673d0c54d9a06b7918e449d36662 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 8 Oct 2009 01:57:54 -0500 Subject: [PATCH 32/63] Doing constant folding on ##neg and ##not in value numbering --- .../value-numbering/rewrite/rewrite.factor | 24 +++++++++++++++- .../value-numbering-tests.factor | 28 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor index 56ec16eed6..4a63777019 100755 --- a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor +++ b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman. +! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators combinators.short-circuit arrays fry kernel layouts math namespaces sequences cpu.architecture @@ -242,6 +242,28 @@ M: ##shl-imm constant-fold* drop shift ; [ [ src1>> vreg>constant ] [ src2>> ] [ ] tri constant-fold* ] bi \ ##load-immediate new-insn ; inline +: unary-constant-fold? ( insn -- ? ) + src>> vreg>expr constant-expr? ; inline + +GENERIC: unary-constant-fold* ( x insn -- y ) + +M: ##not unary-constant-fold* drop bitnot ; +M: ##neg unary-constant-fold* drop neg ; + +: unary-constant-fold ( insn -- insn' ) + [ dst>> ] + [ [ src>> vreg>constant ] [ ] bi unary-constant-fold* ] bi + \ ##load-immediate new-insn ; inline + +: maybe-unary-constant-fold ( insn -- insn' ) + dup unary-constant-fold? [ unary-constant-fold ] [ drop f ] if ; + +M: ##neg rewrite + maybe-unary-constant-fold ; + +M: ##not rewrite + maybe-unary-constant-fold ; + : reassociate ( insn op -- insn ) [ { diff --git a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor index 5f8eda2c08..f98824cb95 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor @@ -983,6 +983,34 @@ cell 8 = [ ] unit-test ] when +[ + { + T{ ##peek f 0 D 0 } + T{ ##load-immediate f 1 1 } + T{ ##load-immediate f 2 -1 } + } +] [ + { + T{ ##peek f 0 D 0 } + T{ ##load-immediate f 1 1 } + T{ ##neg f 2 1 } + } value-numbering-step +] unit-test + +[ + { + T{ ##peek f 0 D 0 } + T{ ##load-immediate f 1 1 } + T{ ##load-immediate f 2 -2 } + } +] [ + { + T{ ##peek f 0 D 0 } + T{ ##load-immediate f 1 1 } + T{ ##not f 2 1 } + } value-numbering-step +] unit-test + ! Displaced alien optimizations 3 vreg-counter set-global From dbf0dd4a2de813dd513bf2204db820212c80c398 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 8 Oct 2009 02:10:28 -0500 Subject: [PATCH 33/63] vm: split off parts of data_gc into sub-files and clean up logic --- vm/aging_collector.cpp | 20 +- vm/aging_collector.hpp | 1 - vm/data_gc.cpp | 534 +----------------------------------- vm/data_gc.hpp | 15 - vm/full_collector.cpp | 76 +++-- vm/full_collector.hpp | 6 +- vm/nursery_collector.cpp | 20 +- vm/nursery_collector.hpp | 1 - vm/to_tenured_collector.cpp | 18 +- vm/vm.hpp | 29 +- 10 files changed, 112 insertions(+), 608 deletions(-) diff --git a/vm/aging_collector.cpp b/vm/aging_collector.cpp index 918d5e322d..287e5c306c 100644 --- a/vm/aging_collector.cpp +++ b/vm/aging_collector.cpp @@ -7,13 +7,21 @@ aging_collector::aging_collector(factor_vm *myvm_) : copying_collector (myvm_,myvm_->data->aging,aging_policy(myvm_)) {} -void aging_collector::go() +void factor_vm::collect_aging() { - trace_roots(); - trace_contexts(); - trace_cards(data->tenured); - trace_code_heap_roots(); - cheneys_algorithm(); + std::swap(data->aging,data->aging_semispace); + reset_generation(data->aging); + + aging_collector collector(this); + + collector.trace_roots(); + collector.trace_contexts(); + collector.trace_cards(data->tenured); + collector.trace_code_heap_roots(); + collector.cheneys_algorithm(); + update_dirty_code_blocks(); + + nursery.here = nursery.start; } } diff --git a/vm/aging_collector.hpp b/vm/aging_collector.hpp index 71b8938710..2191797020 100644 --- a/vm/aging_collector.hpp +++ b/vm/aging_collector.hpp @@ -18,7 +18,6 @@ struct aging_policy { struct aging_collector : copying_collector { aging_collector(factor_vm *myvm_); - void go(); }; } diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 7e3aa95e11..be31636eb7 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -12,345 +12,6 @@ gc_state::gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_ge gc_state::~gc_state() { } -template object *factor_vm::resolve_forwarding(object *untagged, Strategy &strategy) -{ - check_data_pointer(untagged); - - /* is there another forwarding pointer? */ - while(untagged->h.forwarding_pointer_p()) - untagged = untagged->h.forwarding_pointer(); - - /* we've found the destination */ - untagged->h.check_header(); - return untagged; -} - -template void factor_vm::trace_handle(cell *handle, Strategy &strategy) -{ - cell pointer = *handle; - - if(!immediate_p(pointer)) - { - object *untagged = untag(pointer); - if(strategy.should_copy_p(untagged)) - { - object *forwarding = resolve_forwarding(untagged,strategy); - - if(forwarding == untagged) - untagged = strategy.copy_object(untagged); - else if(strategy.should_copy_p(forwarding)) - untagged = strategy.copy_object(forwarding); - else - untagged = forwarding; - - *handle = RETAG(untagged,TAG(pointer)); - } - } -} - -template void factor_vm::trace_slots(object *ptr, Strategy &strategy) -{ - cell *slot = (cell *)ptr; - cell *end = (cell *)((cell)ptr + binary_payload_start(ptr)); - - if(slot != end) - { - slot++; - for(; slot < end; slot++) trace_handle(slot,strategy); - } -} - -template object *factor_vm::promote_object(object *untagged, Strategy &strategy) -{ - cell size = untagged_object_size(untagged); - object *newpointer = strategy.allot(size); - if(!newpointer) longjmp(current_gc->gc_unwind,1); - - generation_statistics *s = &gc_stats.generations[current_gc->collecting_gen]; - s->object_count++; - s->bytes_copied += size; - - memcpy(newpointer,untagged,size); - untagged->h.forward_to(newpointer); - - return newpointer; -} - -template void factor_vm::trace_card(card *ptr, old_space *gen, Strategy &strategy) -{ - cell card_start = card_to_addr(ptr); - cell card_scan = card_start + gen->card_offset(card_start); - cell card_end = card_to_addr(ptr + 1); - - if(gen->here < card_end) card_end = gen->here; - - strategy.copy_reachable_objects(card_scan,&card_end); - - gc_stats.cards_scanned++; -} - -template void factor_vm::trace_card_deck(card_deck *deck, old_space *gen, card mask, card unmask, Strategy &strategy) -{ - card *first_card = deck_to_card(deck); - card *last_card = deck_to_card(deck + 1); - - u32 *quad_ptr; - u32 quad_mask = mask | (mask << 8) | (mask << 16) | (mask << 24); - - for(quad_ptr = (u32 *)first_card; quad_ptr < (u32 *)last_card; quad_ptr++) - { - if(*quad_ptr & quad_mask) - { - card *ptr = (card *)quad_ptr; - - int card; - for(card = 0; card < 4; card++) - { - if(ptr[card] & mask) - { - trace_card(&ptr[card],gen,strategy); - ptr[card] &= ~unmask; - } - } - } - } - - gc_stats.decks_scanned++; -} - -/* Trace all objects referenced from marked cards */ -template void factor_vm::trace_cards(cell gen, old_space *z, Strategy &strategy) -{ - u64 start_time = current_micros(); - - card_deck *first_deck = addr_to_deck(z->start); - card_deck *last_deck = addr_to_deck(z->end); - - card mask, unmask; - - /* if we are collecting the nursery, we care about old->nursery pointers - but not old->aging pointers */ - if(current_gc->collecting_nursery_p()) - { - mask = card_points_to_nursery; - - /* after the collection, no old->nursery pointers remain - anywhere, but old->aging pointers might remain in tenured - space */ - if(gen == tenured_gen) - unmask = card_points_to_nursery; - /* after the collection, all cards in aging space can be - cleared */ - else if(gen == aging_gen) - unmask = card_mark_mask; - else - { - critical_error("bug in trace_generation_cards",gen); - return; - } - } - /* if we are collecting aging space into tenured space, we care about - all old->nursery and old->aging pointers. no old->aging pointers can - remain */ - else if(current_gc->collecting_aging_p()) - { - if(current_gc->collecting_aging_again) - { - mask = card_points_to_aging; - unmask = card_mark_mask; - } - /* after we collect aging space into the aging semispace, no - old->nursery pointers remain but tenured space might still have - pointers to aging space. */ - else - { - mask = card_points_to_aging; - unmask = card_points_to_nursery; - } - } - else - { - critical_error("bug in trace_generation_cards",gen); - return; - } - - card_deck *ptr; - - for(ptr = first_deck; ptr < last_deck; ptr++) - { - if(*ptr & mask) - { - trace_card_deck(ptr,z,mask,unmask,strategy); - *ptr &= ~unmask; - } - } - - gc_stats.card_scan_time += (current_micros() - start_time); -} - -/* Copy all tagged pointers in a range of memory */ -template void factor_vm::trace_stack_elements(segment *region, cell top, Strategy &strategy) -{ - cell ptr = region->start; - - for(; ptr <= top; ptr += sizeof(cell)) - trace_handle((cell*)ptr,strategy); -} - -template void factor_vm::trace_registered_locals(Strategy &strategy) -{ - std::vector::const_iterator iter = gc_locals.begin(); - std::vector::const_iterator end = gc_locals.end(); - - for(; iter < end; iter++) - trace_handle((cell *)(*iter),strategy); -} - -template void factor_vm::trace_registered_bignums(Strategy &strategy) -{ - std::vector::const_iterator iter = gc_bignums.begin(); - std::vector::const_iterator end = gc_bignums.end(); - - for(; iter < end; iter++) - { - cell *handle = (cell *)(*iter); - - if(*handle) - { - *handle |= BIGNUM_TYPE; - trace_handle(handle,strategy); - *handle &= ~BIGNUM_TYPE; - } - } -} - -/* Copy roots over at the start of GC, namely various constants, stacks, -the user environment and extra roots registered by local_roots.hpp */ -template void factor_vm::trace_roots(Strategy &strategy) -{ - trace_handle(&T,strategy); - trace_handle(&bignum_zero,strategy); - trace_handle(&bignum_pos_one,strategy); - trace_handle(&bignum_neg_one,strategy); - - trace_registered_locals(strategy); - trace_registered_bignums(strategy); - - int i; - for(i = 0; i < USER_ENV; i++) - trace_handle(&userenv[i],strategy); -} - -template struct stack_frame_marker { - factor_vm *myvm; - Strategy &strategy; - - explicit stack_frame_marker(factor_vm *myvm_, Strategy &strategy_) : - myvm(myvm_), strategy(strategy_) {} - void operator()(stack_frame *frame) - { - myvm->mark_code_block(myvm->frame_code(frame),strategy); - } -}; - -/* Mark code blocks executing in currently active stack frames. */ -template void factor_vm::mark_active_blocks(context *stacks, Strategy &strategy) -{ - if(current_gc->collecting_tenured_p()) - { - cell top = (cell)stacks->callstack_top; - cell bottom = (cell)stacks->callstack_bottom; - - stack_frame_marker marker(this,strategy); - iterate_callstack(top,bottom,marker); - } -} - -template void factor_vm::mark_object_code_block(object *object, Strategy &strategy) -{ - switch(object->h.hi_tag()) - { - case WORD_TYPE: - { - word *w = (word *)object; - if(w->code) - mark_code_block(w->code,strategy); - if(w->profiling) - mark_code_block(w->profiling,strategy); - break; - } - case QUOTATION_TYPE: - { - quotation *q = (quotation *)object; - if(q->code) - mark_code_block(q->code,strategy); - break; - } - case CALLSTACK_TYPE: - { - callstack *stack = (callstack *)object; - stack_frame_marker marker(this,strategy); - iterate_callstack_object(stack,marker); - break; - } - } -} - -template void factor_vm::trace_contexts(Strategy &strategy) -{ - save_stacks(); - context *stacks = stack_chain; - - while(stacks) - { - trace_stack_elements(stacks->datastack_region,stacks->datastack,strategy); - trace_stack_elements(stacks->retainstack_region,stacks->retainstack,strategy); - - trace_handle(&stacks->catchstack_save,strategy); - trace_handle(&stacks->current_callback_save,strategy); - - mark_active_blocks(stacks,strategy); - - stacks = stacks->next; - } -} - -/* Trace all literals referenced from a code block. Only for aging and nursery collections */ -template void factor_vm::trace_literal_references(code_block *compiled, Strategy &strategy) -{ - trace_handle(&compiled->owner,strategy); - trace_handle(&compiled->literals,strategy); - trace_handle(&compiled->relocation,strategy); -} - -/* Trace literals referenced from all code blocks. Only for aging and nursery collections */ -template void factor_vm::trace_code_heap_roots(Strategy &strategy) -{ - if(current_gc->collecting_gen >= code->youngest_referenced_generation) - { - unordered_map::const_iterator iter = code->remembered_set.begin(); - unordered_map::const_iterator end = code->remembered_set.end(); - - for(; iter != end; iter++) - { - if(current_gc->collecting_gen >= iter->second) - trace_literal_references(iter->first,strategy); - } - - gc_stats.code_heap_scans++; - } -} - -/* Mark all literals referenced from a word XT. Only for tenured -collections */ -template void factor_vm::mark_code_block(code_block *compiled, Strategy &strategy) -{ - check_code_address((cell)compiled); - - code->mark_block(compiled); - trace_literal_references(compiled,strategy); -} - struct literal_and_word_reference_updater { factor_vm *myvm; @@ -398,193 +59,6 @@ void factor_vm::update_dirty_code_blocks() code->youngest_referenced_generation = gen; } -template -cheney_collector::cheney_collector(factor_vm *myvm_, old_space *target_) -: myvm(myvm_), current_gc(myvm_->current_gc), target(target_) -{ - scan = target->here; -} - -template Strategy &cheney_collector::strategy() -{ - return static_cast(*this); -} - -template object *cheney_collector::allot(cell size) -{ - return target->allot(size); -} - -template object *cheney_collector::copy_object(object *untagged) -{ - return myvm->promote_object(untagged,strategy()); -} - -template bool cheney_collector::should_copy_p(object *pointer) -{ - return strategy().should_copy_p(pointer); -} - -template cell cheney_collector::trace_next(cell scan) -{ - object *obj = (object *)scan; - myvm->trace_slots(obj,strategy()); - return scan + myvm->untagged_object_size(obj); -} - -template void cheney_collector::go() -{ - strategy().copy_reachable_objects(scan,&target->here); -} - -struct nursery_strategy : cheney_collector -{ - explicit nursery_strategy(factor_vm *myvm_, old_space *target_) : - cheney_collector(myvm_,target_) {} - - bool should_copy_p(object *untagged) - { - return myvm->nursery.contains_p(untagged); - } - - void copy_reachable_objects(cell scan, cell *end) - { - while(scan < *end) scan = trace_next(scan); - } -}; - -struct aging_strategy : cheney_collector -{ - zone *tenured; - - explicit aging_strategy(factor_vm *myvm_, old_space *target_) : - cheney_collector(myvm_,target_), - tenured(myvm->data->tenured) {} - - bool should_copy_p(object *untagged) - { - if(target->contains_p(untagged)) - return false; - else - return !tenured->contains_p(untagged); - } - - void copy_reachable_objects(cell scan, cell *end) - { - while(scan < *end) scan = trace_next(scan); - } -}; - -struct aging_agian_strategy : cheney_collector -{ - explicit aging_agian_strategy(factor_vm *myvm_, old_space *target_) : - cheney_collector(myvm_,target_) {} - - bool should_copy_p(object *untagged) - { - return !target->contains_p(untagged); - } - - void copy_reachable_objects(cell scan, cell *end) - { - while(scan < *end) scan = trace_next(scan); - } -}; - -struct tenured_strategy : cheney_collector -{ - explicit tenured_strategy(factor_vm *myvm_, old_space *target_) : - cheney_collector(myvm_,target_) {} - - bool should_copy_p(object *untagged) - { - return !target->contains_p(untagged); - } - - void copy_reachable_objects(cell scan, cell *end) - { - while(scan < *end) - { - myvm->mark_object_code_block(myvm->untag(scan),*this); - scan = trace_next(scan); - } - } -}; - -void factor_vm::collect_nursery() -{ - nursery_strategy collector(this,data->aging); - - trace_roots(collector); - trace_contexts(collector); - trace_cards(tenured_gen,data->tenured,collector); - trace_cards(aging_gen,data->aging,collector); - trace_code_heap_roots(collector); - collector.go(); - update_dirty_code_blocks(); - - nursery.here = nursery.start; -} - -void factor_vm::collect_aging() -{ - std::swap(data->aging,data->aging_semispace); - reset_generation(data->aging); - - aging_strategy collector(this,data->aging); - - trace_roots(collector); - trace_contexts(collector); - trace_cards(tenured_gen,data->tenured,collector); - trace_code_heap_roots(collector); - collector.go(); - update_dirty_code_blocks(); - - nursery.here = nursery.start; -} - -void factor_vm::collect_aging_again() -{ - aging_agian_strategy collector(this,data->tenured); - - trace_roots(collector); - trace_contexts(collector); - trace_cards(tenured_gen,data->tenured,collector); - trace_code_heap_roots(collector); - collector.go(); - update_dirty_code_blocks(); - - reset_generation(data->aging); - nursery.here = nursery.start; -} - -void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_) -{ - if(current_gc->growing_data_heap) - { - current_gc->old_data_heap = data; - set_data_heap(grow_data_heap(current_gc->old_data_heap,requested_bytes)); - } - else - { - std::swap(data->tenured,data->tenured_semispace); - reset_generation(data->tenured); - } - - tenured_strategy collector(this,data->tenured); - - trace_roots(collector); - if(trace_contexts_) trace_contexts(collector); - collector.go(); - free_unmarked_code_blocks(); - - reset_generation(data->aging); - nursery.here = nursery.start; - - if(current_gc->growing_data_heap) - delete current_gc->old_data_heap; -} - void factor_vm::record_gc_stats() { generation_statistics *s = &gc_stats.generations[current_gc->collecting_gen]; @@ -599,11 +73,13 @@ void factor_vm::record_gc_stats() /* Collect gen and all younger generations. If growing_data_heap_ is true, we must grow the data heap to such a size that an allocation of requested_bytes won't fail */ -void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_, bool trace_contexts_, cell requested_bytes) +void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_, bool trace_contexts_p, cell requested_bytes) { assert(!gc_off); assert(!current_gc); + save_stacks(); + current_gc = new gc_state(data,growing_data_heap_,collecting_gen_); /* Keep trying to GC higher and higher generations until we don't run out @@ -640,12 +116,12 @@ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_ else if(current_gc->collecting_aging_p()) { if(current_gc->collecting_aging_again) - collect_aging_again(); + collect_to_tenured(); else collect_aging(); } else if(current_gc->collecting_tenured_p()) - collect_tenured(requested_bytes,trace_contexts_); + collect_full(requested_bytes,trace_contexts_p); record_gc_stats(); diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index d9bed8e785..9304a3ad03 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -63,21 +63,6 @@ struct gc_state { } }; -template struct cheney_collector { - factor_vm *myvm; - gc_state *current_gc; - old_space *target; - cell scan; - - explicit cheney_collector(factor_vm *myvm_, old_space *target); - Strategy &strategy(); - object *allot(cell size); - cell trace_next(cell scan); - object *copy_object(object *untagged); - bool should_copy_p(object *untagged); - void go(); -}; - VM_C_API void inline_gc(cell *gc_roots_base, cell gc_roots_size, factor_vm *myvm); } diff --git a/vm/full_collector.cpp b/vm/full_collector.cpp index bead2f7338..c54dd6b72e 100644 --- a/vm/full_collector.cpp +++ b/vm/full_collector.cpp @@ -3,9 +3,8 @@ namespace factor { -full_collector::full_collector(factor_vm *myvm_, bool trace_contexts_p_) : - copying_collector(myvm_,myvm_->data->tenured,full_policy(myvm_)), - trace_contexts_p(trace_contexts_p_) {} +full_collector::full_collector(factor_vm *myvm_) : + copying_collector(myvm_,myvm_->data->tenured,full_policy(myvm_)) {} struct stack_frame_marker { factor_vm *myvm; @@ -21,22 +20,29 @@ struct stack_frame_marker { }; /* Mark code blocks executing in currently active stack frames. */ -void full_collector::mark_active_blocks(context *stacks) +void full_collector::mark_active_blocks() { - cell top = (cell)stacks->callstack_top; - cell bottom = (cell)stacks->callstack_bottom; + context *stacks = this->myvm->stack_chain; - stack_frame_marker marker(this); - myvm->iterate_callstack(top,bottom,marker); + while(stacks) + { + cell top = (cell)stacks->callstack_top; + cell bottom = (cell)stacks->callstack_bottom; + + stack_frame_marker marker(this); + myvm->iterate_callstack(top,bottom,marker); + + stacks = stacks->next; + } } -void full_collector::mark_object_code_block(object *object) +void full_collector::mark_object_code_block(object *obj) { - switch(object->h.hi_tag()) + switch(obj->h.hi_tag()) { case WORD_TYPE: { - word *w = (word *)object; + word *w = (word *)obj; if(w->code) mark_code_block(w->code); if(w->profiling) @@ -45,14 +51,14 @@ void full_collector::mark_object_code_block(object *object) } case QUOTATION_TYPE: { - quotation *q = (quotation *)object; + quotation *q = (quotation *)obj; if(q->code) mark_code_block(q->code); break; } case CALLSTACK_TYPE: { - callstack *stack = (callstack *)object; + callstack *stack = (callstack *)obj; stack_frame_marker marker(this); myvm->iterate_callstack_object(stack,marker); break; @@ -78,11 +84,47 @@ void full_collector::mark_code_block(code_block *compiled) trace_literal_references(compiled); } -void full_collector::go() +void full_collector::cheneys_algorithm() { - trace_roots(); - if(trace_contexts_p) trace_contexts(); - cheneys_algorithm(); + while(scan && scan < target->here) + { + object *obj = (object *)scan; + this->trace_slots(obj); + this->mark_object_code_block(obj); + scan = target->next_object_after(this->myvm,scan); + } +} + +void factor_vm::collect_full(cell requested_bytes, bool trace_contexts_p) +{ + if(current_gc->growing_data_heap) + { + current_gc->old_data_heap = data; + set_data_heap(grow_data_heap(current_gc->old_data_heap,requested_bytes)); + } + else + { + std::swap(data->tenured,data->tenured_semispace); + reset_generation(data->tenured); + } + + full_collector collector(this); + + collector.trace_roots(); + if(trace_contexts_p) + { + collector.trace_contexts(); + collector.mark_active_blocks(); + } + + collector.cheneys_algorithm(); + free_unmarked_code_blocks(); + + reset_generation(data->aging); + nursery.here = nursery.start; + + if(current_gc->growing_data_heap) + delete current_gc->old_data_heap; } } diff --git a/vm/full_collector.hpp b/vm/full_collector.hpp index d5c47416fa..d39358e0e2 100644 --- a/vm/full_collector.hpp +++ b/vm/full_collector.hpp @@ -16,12 +16,12 @@ struct full_policy { struct full_collector : copying_collector { bool trace_contexts_p; - full_collector(factor_vm *myvm_, bool trace_contexts_p_); - void mark_active_blocks(context *stacks); + full_collector(factor_vm *myvm_); + void mark_active_blocks(); void mark_object_code_block(object *object); void trace_literal_references(code_block *compiled); void mark_code_block(code_block *compiled); - void go(); + void cheneys_algorithm(); }; } diff --git a/vm/nursery_collector.cpp b/vm/nursery_collector.cpp index 302f958562..f5dc386053 100644 --- a/vm/nursery_collector.cpp +++ b/vm/nursery_collector.cpp @@ -7,14 +7,20 @@ nursery_collector::nursery_collector(factor_vm *myvm_) : copying_collector (myvm_,myvm_->data->aging,nursery_policy(myvm_)) {} -void nursery_collector::go() +void factor_vm::collect_nursery() { - trace_roots(); - trace_contexts(); - trace_cards(data->tenured); - trace_cards(data->aging); - trace_code_heap_roots(); - cheneys_algorithm(); + nursery_collector collector(this); + + collector.trace_roots(); + collector.trace_contexts(); + collector.trace_cards(data->tenured); + collector.trace_cards(data->aging); + collector.trace_code_heap_roots(); + collector.cheneys_algorithm(); + + update_dirty_code_blocks(); + + nursery.here = nursery.start; } } diff --git a/vm/nursery_collector.hpp b/vm/nursery_collector.hpp index 1cfe063187..cff988cf9d 100644 --- a/vm/nursery_collector.hpp +++ b/vm/nursery_collector.hpp @@ -14,7 +14,6 @@ struct nursery_policy { struct nursery_collector : copying_collector { nursery_collector(factor_vm *myvm_); - void go(); }; } diff --git a/vm/to_tenured_collector.cpp b/vm/to_tenured_collector.cpp index 2693e35a2f..a0341ec93d 100644 --- a/vm/to_tenured_collector.cpp +++ b/vm/to_tenured_collector.cpp @@ -7,13 +7,19 @@ to_tenured_collector::to_tenured_collector(factor_vm *myvm_) : copying_collector (myvm_,myvm_->data->tenured,to_tenured_policy(myvm_)) {} -void to_tenured_collector::go() +void factor_vm::collect_to_tenured() { - trace_roots(); - trace_contexts(); - trace_cards(data->tenured); - trace_code_heap_roots(); - cheneys_algorithm(); + to_tenured_collector collector(this); + + collector.trace_roots(); + collector.trace_contexts(); + collector.trace_cards(data->tenured); + collector.trace_code_heap_roots(); + collector.cheneys_algorithm(); + update_dirty_code_blocks(); + + reset_generation(data->aging); + nursery.here = nursery.start; } } diff --git a/vm/vm.hpp b/vm/vm.hpp index 02ab128969..80dd67c76d 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -205,7 +205,7 @@ struct factor_vm int bignum_unsigned_logbitp(int shift, bignum * bignum); bignum *digit_stream_to_bignum(unsigned int n_digits, unsigned int (*producer)(unsigned int, factor_vm *), unsigned int radix, int negative_p); - //data_heap + //data heap void init_card_decks(); data_heap *grow_data_heap(data_heap *data, cell requested_bytes); void clear_cards(old_space *gen); @@ -262,32 +262,15 @@ struct factor_vm *addr_to_deck((cell)obj) = card_mark_mask; } - // data_gc - template object *resolve_forwarding(object *untagged, Strategy &strategy); - template void trace_handle(cell *handle, Strategy &strategy); - template object *promote_object(object *pointer, Strategy &strategy); - template void trace_slots(object *ptr, Strategy &strategy); - template void trace_card(card *ptr, old_space *gen, Strategy &strategy); - template void trace_card_deck(card_deck *deck, old_space *gen, card mask, card unmask, Strategy &strategy); - template void trace_cards(cell gen, old_space *z, Strategy &strategy); - template void trace_stack_elements(segment *region, cell top, Strategy &strategy); - template void trace_registered_locals(Strategy &strategy); - template void trace_registered_bignums(Strategy &strategy); - template void trace_roots(Strategy &strategy); - template void mark_active_blocks(context *stacks, Strategy &strategy); - template void trace_contexts(Strategy &strategy); - template void trace_literal_references(code_block *compiled, Strategy &strategy); - template void trace_code_heap_roots(Strategy &strategy); - template void mark_code_block(code_block *compiled, Strategy &strategy); - template void mark_object_code_block(object *object, Strategy &strategy); + // gc void free_unmarked_code_blocks(); void update_dirty_code_blocks(); void collect_nursery(); void collect_aging(); - void collect_aging_again(); - void collect_tenured(cell requested_bytes, bool trace_contexts_); + void collect_to_tenured(); + void collect_full(cell requested_bytes, bool trace_contexts_p); void record_gc_stats(); - void garbage_collection(cell gen, bool growing_data_heap, bool trace_contexts, cell requested_bytes); + void garbage_collection(cell gen, bool growing_data_heap, bool trace_contexts_p, cell requested_bytes); void gc(); void primitive_gc(); void primitive_gc_stats(); @@ -528,7 +511,7 @@ struct factor_vm code_block *allot_code_block(cell size, cell type); code_block *add_code_block(cell type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_); - //code_heap + //code heap inline void check_code_pointer(cell ptr) { #ifdef FACTOR_DEBUG From 43a21deb05e880fdc8df25543a43c620b0da54f1 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 8 Oct 2009 02:11:29 -0500 Subject: [PATCH 34/63] vm: rename data_gc.cpp to gc.cpp --- Makefile | 2 +- vm/{data_gc.cpp => gc.cpp} | 0 vm/{data_gc.hpp => gc.hpp} | 0 vm/master.hpp | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) rename vm/{data_gc.cpp => gc.cpp} (100%) rename vm/{data_gc.hpp => gc.hpp} (100%) diff --git a/Makefile b/Makefile index 0b16233b63..f9eb353a34 100755 --- a/Makefile +++ b/Makefile @@ -41,13 +41,13 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \ vm/code_block.o \ vm/code_heap.o \ vm/contexts.o \ - vm/data_gc.o \ vm/data_heap.o \ vm/debug.o \ vm/dispatch.o \ vm/errors.o \ vm/factor.o \ vm/full_collector.o \ + vm/gc.o \ vm/heap.o \ vm/image.o \ vm/inline_cache.o \ diff --git a/vm/data_gc.cpp b/vm/gc.cpp similarity index 100% rename from vm/data_gc.cpp rename to vm/gc.cpp diff --git a/vm/data_gc.hpp b/vm/gc.hpp similarity index 100% rename from vm/data_gc.hpp rename to vm/gc.hpp diff --git a/vm/master.hpp b/vm/master.hpp index 0e8a03fff6..fbafaf2d7b 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -75,7 +75,7 @@ namespace factor #include "aging_space.hpp" #include "tenured_space.hpp" #include "data_heap.hpp" -#include "data_gc.hpp" +#include "gc.hpp" #include "debug.hpp" #include "strings.hpp" #include "tuples.hpp" From db927ff0ad1aecbfcc0fcc10034c1b6060d21b13 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 8 Oct 2009 13:10:51 -0500 Subject: [PATCH 35/63] Making struct bitfield writers fast --- .../bit-accessors/bit-accessors-tests.factor | 7 +++++ .../struct/bit-accessors/bit-accessors.factor | 30 ++++++++++++++++--- basis/classes/struct/struct.factor | 20 ++----------- 3 files changed, 36 insertions(+), 21 deletions(-) create mode 100644 basis/classes/struct/bit-accessors/bit-accessors-tests.factor diff --git a/basis/classes/struct/bit-accessors/bit-accessors-tests.factor b/basis/classes/struct/bit-accessors/bit-accessors-tests.factor new file mode 100644 index 0000000000..e2ff6dbd9c --- /dev/null +++ b/basis/classes/struct/bit-accessors/bit-accessors-tests.factor @@ -0,0 +1,7 @@ +! Copyright (C) 2009 Daniel Ehrenberg +! See http://factorcode.org/license.txt for BSD license. +USING: classes.struct.bit-accessors tools.test effects kernel random stack-checker ; +IN: classes.struct.bit-accessors.test + +[ t ] [ 20 random 20 random bit-reader infer (( alien -- n )) effect= ] unit-test +[ t ] [ 20 random 20 random bit-writer infer (( n alien -- )) effect= ] unit-test diff --git a/basis/classes/struct/bit-accessors/bit-accessors.factor b/basis/classes/struct/bit-accessors/bit-accessors.factor index 9d625beab3..04757a233a 100644 --- a/basis/classes/struct/bit-accessors/bit-accessors.factor +++ b/basis/classes/struct/bit-accessors/bit-accessors.factor @@ -9,15 +9,15 @@ IN: classes.struct.bit-accessors : ones-between ( start end -- n ) [ 2^ 1 - ] bi@ swap bitnot bitand ; -:: read-bits ( offset bits -- quot: ( byte-array -- n ) shift-amount offset' bits' ) +: ones-around ( start end -- n ) + ones-between bitnot ; + +:: read-bits ( offset bits -- quot: ( alien -- n ) shift-amount offset' bits' ) offset 8 /mod :> start-bit :> i start-bit bits + 8 min :> end-bit start-bit end-bit ones-between :> mask end-bit start-bit - :> used-bits - ! The code generated for this isn't optimal - ! To improve the code, algebraic simplifications should - ! have interval information available [ i alien-unsigned-1 mask bitand start-bit neg shift ] used-bits i 1 + 8 * @@ -27,3 +27,25 @@ IN: classes.struct.bit-accessors read-bits dup zero? [ 3drop ] [ bit-reader swap '[ _ _ bi _ shift bitor ] ] if ; + +:: write-bits ( offset bits -- quot: ( alien -- n ) shift-amount offset' bits' ) + offset 8 /mod :> start-bit :> i + start-bit bits + 8 min :> end-bit + start-bit end-bit ones-between :> mask + end-bit start-bit - :> used-bits + + [ + [ + [ start-bit shift mask bitand ] + [ i alien-unsigned-1 mask bitnot bitand ] + bi* bitor + ] keep i set-alien-unsigned-1 + ] + used-bits + i 1 + 8 * + bits used-bits - ; + +: bit-writer ( offset bits -- quot: ( n alien -- ) ) + write-bits dup zero? [ 3drop ] [ + bit-writer '[ _ [ [ _ neg shift ] dip @ ] 2bi ] + ] if ; diff --git a/basis/classes/struct/struct.factor b/basis/classes/struct/struct.factor index 6593e8350d..af23834383 100755 --- a/basis/classes/struct/struct.factor +++ b/basis/classes/struct/struct.factor @@ -116,23 +116,9 @@ M: struct-slot-spec (writer-quot) [ type>> c-setter ] [ offset>> [ >c-ptr ] swap suffix ] bi prepend ; -QUALIFIED: math.bits - -: bytes>bits ( byte-array -- bit-array ) - [ 8 math.bits: ] { } map-as ?{ } join ; - -: (write-bits) ( value offset end byte-array -- ) - ! This is absurdly inefficient - [ - [ [ swap - math.bits: ] 2keep ] [ bytes>bits ] bi* - replace-slice ?{ } like underlying>> - ] keep 0 swap copy ; - -: bits@ ( slot -- beginning end ) - [ offset>> ] [ bits>> ] bi dupd + ; - -M: struct-bit-slot-spec (writer-quot) ( slot -- quot ) - bits@ '[ [ _ _ ] dip (underlying)>> (write-bits) ] ; +M: struct-bit-slot-spec (writer-quot) + [ offset>> ] [ bits>> ] bi bit-writer + [ >c-ptr ] prepose ; : (boxer-quot) ( class -- quot ) '[ _ memory>struct ] ; From 8841969ca1bb0cd410dae32426fca28c252ec47c Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 8 Oct 2009 13:45:52 -0500 Subject: [PATCH 36/63] Refactoring bitfield accessors to eliminate code duplication --- .../struct/bit-accessors/bit-accessors.factor | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/basis/classes/struct/bit-accessors/bit-accessors.factor b/basis/classes/struct/bit-accessors/bit-accessors.factor index 04757a233a..30620b46c1 100644 --- a/basis/classes/struct/bit-accessors/bit-accessors.factor +++ b/basis/classes/struct/bit-accessors/bit-accessors.factor @@ -9,43 +9,43 @@ IN: classes.struct.bit-accessors : ones-between ( start end -- n ) [ 2^ 1 - ] bi@ swap bitnot bitand ; -: ones-around ( start end -- n ) - ones-between bitnot ; - -:: read-bits ( offset bits -- quot: ( alien -- n ) shift-amount offset' bits' ) +:: manipulate-bits ( offset bits step-quot -- quot shift-amount offset' bits' ) offset 8 /mod :> start-bit :> i start-bit bits + 8 min :> end-bit start-bit end-bit ones-between :> mask end-bit start-bit - :> used-bits - [ i alien-unsigned-1 mask bitand start-bit neg shift ] + start-bit i end-bit mask step-quot call( a b c d -- quot ) used-bits i 1 + 8 * - bits used-bits - ; + bits used-bits - ; inline + +:: bit-manipulator ( offset bits + step-quot: ( start-bit i end-bit mask -- quot ) + combine-quot: ( prev-quot shift-amount next-quot -- quot ) + -- quot ) + offset bits step-quot manipulate-bits + dup zero? [ 3drop ] [ + step-quot combine-quot bit-manipulator + combine-quot call( prev shift next -- quot ) + ] if ; inline recursive : bit-reader ( offset bits -- quot: ( alien -- n ) ) - read-bits dup zero? [ 3drop ] [ - bit-reader swap '[ _ _ bi _ shift bitor ] - ] if ; - -:: write-bits ( offset bits -- quot: ( alien -- n ) shift-amount offset' bits' ) - offset 8 /mod :> start-bit :> i - start-bit bits + 8 min :> end-bit - start-bit end-bit ones-between :> mask - end-bit start-bit - :> used-bits - - [ - [ - [ start-bit shift mask bitand ] - [ i alien-unsigned-1 mask bitnot bitand ] - bi* bitor - ] keep i set-alien-unsigned-1 + [| start-bit i end-bit mask | + [ i alien-unsigned-1 mask bitand start-bit neg shift ] ] - used-bits - i 1 + 8 * - bits used-bits - ; + [ swap '[ _ _ bi _ shift bitor ] ] + bit-manipulator ; : bit-writer ( offset bits -- quot: ( n alien -- ) ) - write-bits dup zero? [ 3drop ] [ - bit-writer '[ _ [ [ _ neg shift ] dip @ ] 2bi ] - ] if ; + [| start-bit i end-bit mask | + [ + [ + [ start-bit shift mask bitand ] + [ i alien-unsigned-1 mask bitnot bitand ] + bi* bitor + ] keep i set-alien-unsigned-1 + ] + ] + [ '[ _ [ [ _ neg shift ] dip @ ] 2bi ] ] + bit-manipulator ; From 891b7c98044aba1f2522b7c8038cb3742b2d8a46 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 8 Oct 2009 14:01:43 -0500 Subject: [PATCH 37/63] Cleaning up classes.struct.bit-accessors code --- .../struct/bit-accessors/bit-accessors.factor | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/basis/classes/struct/bit-accessors/bit-accessors.factor b/basis/classes/struct/bit-accessors/bit-accessors.factor index 30620b46c1..7a2fdb0cac 100644 --- a/basis/classes/struct/bit-accessors/bit-accessors.factor +++ b/basis/classes/struct/bit-accessors/bit-accessors.factor @@ -15,13 +15,13 @@ IN: classes.struct.bit-accessors start-bit end-bit ones-between :> mask end-bit start-bit - :> used-bits - start-bit i end-bit mask step-quot call( a b c d -- quot ) + i mask start-bit step-quot call( i mask start-bit -- quot ) used-bits i 1 + 8 * bits used-bits - ; inline :: bit-manipulator ( offset bits - step-quot: ( start-bit i end-bit mask -- quot ) + step-quot: ( i mask start-bit -- quot ) combine-quot: ( prev-quot shift-amount next-quot -- quot ) -- quot ) offset bits step-quot manipulate-bits @@ -31,21 +31,16 @@ IN: classes.struct.bit-accessors ] if ; inline recursive : bit-reader ( offset bits -- quot: ( alien -- n ) ) - [| start-bit i end-bit mask | - [ i alien-unsigned-1 mask bitand start-bit neg shift ] - ] + [ neg '[ _ alien-unsigned-1 _ bitand _ shift ] ] [ swap '[ _ _ bi _ shift bitor ] ] bit-manipulator ; +:: write-bits ( n alien i mask start-bit -- ) + n start-bit shift mask bitand + alien i alien-unsigned-1 mask bitnot bitand + bitor alien i set-alien-unsigned-1 ; inline + : bit-writer ( offset bits -- quot: ( n alien -- ) ) - [| start-bit i end-bit mask | - [ - [ - [ start-bit shift mask bitand ] - [ i alien-unsigned-1 mask bitnot bitand ] - bi* bitor - ] keep i set-alien-unsigned-1 - ] - ] + [ '[ _ _ _ write-bits ] ] [ '[ _ [ [ _ neg shift ] dip @ ] 2bi ] ] bit-manipulator ; From bb9354305426be1189e6d2d9120f50ba4b4bdb4e Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 8 Oct 2009 15:20:42 -0500 Subject: [PATCH 38/63] Another identity in value numbering for bitfields --- .../struct/bit-accessors/bit-accessors.factor | 2 +- .../tree/propagation/propagation-tests.factor | 4 +++ .../propagation/transforms/transforms.factor | 29 +++++++++++++++---- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/basis/classes/struct/bit-accessors/bit-accessors.factor b/basis/classes/struct/bit-accessors/bit-accessors.factor index 7a2fdb0cac..c535e52c0a 100644 --- a/basis/classes/struct/bit-accessors/bit-accessors.factor +++ b/basis/classes/struct/bit-accessors/bit-accessors.factor @@ -4,7 +4,7 @@ USING: kernel sequences math fry locals math.order alien.accessors ; IN: classes.struct.bit-accessors ! Bitfield accessors are little-endian on all platforms -! Why not? It's platform-dependent in C +! Why not? It's unspecified in C : ones-between ( start end -- n ) [ 2^ 1 - ] bi@ swap bitnot bitand ; diff --git a/basis/compiler/tree/propagation/propagation-tests.factor b/basis/compiler/tree/propagation/propagation-tests.factor index c1b6691542..0a8cb61a9f 100644 --- a/basis/compiler/tree/propagation/propagation-tests.factor +++ b/basis/compiler/tree/propagation/propagation-tests.factor @@ -902,3 +902,7 @@ M: tuple-with-read-only-slot clone [ t ] [ [ alien-unsigned-1 255 bitand ] { bitand fixnum-bitand } inlined? ] unit-test [ t ] [ [ alien-unsigned-1 255 swap bitand ] { bitand fixnum-bitand } inlined? ] unit-test + +[ t ] [ [ { fixnum } declare 256 rem -256 bitand ] { fixnum-bitand } inlined? ] unit-test +[ t ] [ [ { fixnum } declare 250 rem -256 bitand ] { fixnum-bitand } inlined? ] unit-test +[ f ] [ [ { fixnum } declare 257 rem -256 bitand ] { fixnum-bitand } inlined? ] unit-test diff --git a/basis/compiler/tree/propagation/transforms/transforms.factor b/basis/compiler/tree/propagation/transforms/transforms.factor index 08ac306248..b8ff96f833 100644 --- a/basis/compiler/tree/propagation/transforms/transforms.factor +++ b/basis/compiler/tree/propagation/transforms/transforms.factor @@ -45,13 +45,26 @@ IN: compiler.tree.propagation.transforms : simplify-bitand? ( value -- ? ) value-info literal>> positive-fixnum? ; +: all-ones? ( int -- ? ) + dup 1 + bitand zero? ; inline + : redundant-bitand? ( var 111... -- ? ) - [ value-info ] bi@ { [ - nip literal>> - { [ positive-fixnum? ] [ dup 1 + bitand zero? ] } 1&& - ] [ - [ interval>> ] [ literal>> ] bi* 0 swap [a,b] interval-subset? - ] } 2&& ; + [ value-info ] bi@ [ interval>> ] [ literal>> ] bi* { + [ nip integer? ] + [ nip all-ones? ] + [ 0 swap [a,b] interval-subset? ] + } 2&& ; + +: (zero-bitand?) ( value-info value-info' -- ? ) + [ interval>> ] [ literal>> ] bi* { + [ nip integer? ] + [ nip bitnot all-ones? ] + [ 0 swap bitnot [a,b] interval-subset? ] + } 2&& ; + +: zero-bitand? ( var1 var2 -- ? ) + [ value-info ] bi@ + { [ (zero-bitand?) ] [ swap (zero-bitand?) ] } 2|| ; { bitand-integer-integer @@ -61,6 +74,10 @@ IN: compiler.tree.propagation.transforms } [ [ { + { + [ dup in-d>> first2 zero-bitand? ] + [ drop [ 2drop 0 ] ] + } { [ dup in-d>> first2 redundant-bitand? ] [ drop [ drop ] ] From 37d0f29e4b1c3ecfe8f3d04afd977d61c889e527 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Thu, 8 Oct 2009 16:07:36 -0500 Subject: [PATCH 39/63] add a couple of combinators to mmap that take a c-type to reduce conceptual overhead and boilerplate, more docs --- basis/io/mmap/mmap-docs.factor | 55 +++++++++++++++++++++++----- basis/io/mmap/mmap.factor | 19 ++++++++-- basis/io/mmap/unix/unix.factor | 4 +- basis/io/mmap/windows/windows.factor | 2 +- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/basis/io/mmap/mmap-docs.factor b/basis/io/mmap/mmap-docs.factor index c87a3552e4..3379a2879b 100644 --- a/basis/io/mmap/mmap-docs.factor +++ b/basis/io/mmap/mmap-docs.factor @@ -1,5 +1,6 @@ -USING: help.markup help.syntax alien math continuations -destructors specialized-arrays ; +USING: alien alien.c-types continuations destructors +help.markup help.syntax kernel math quotations +specialized-arrays ; IN: io.mmap HELP: mapped-file @@ -33,9 +34,42 @@ HELP: close-mapped-file { $contract "Releases system resources associated with the mapped file. This word should not be called by user code; use " { $link dispose } " instead." } { $errors "Throws an error if a memory mapping could not be established." } ; +HELP: +{ $values { "path" "a pathname string" } { "mmap" mapped-file } } +{ $contract "Opens a file for reading only and maps its contents into memory. The length is permitted to exceed the length of the file on disk, in which case the remaining space is padded with zero bytes." } +{ $notes "You must call " { $link dispose } " when you are finished working with the returned object, to reclaim resources. The " { $link with-mapped-file } " provides an abstraction which can close the mapped file for you." } +{ $errors "Throws an error if a memory mapping could not be established." } ; + +HELP: with-mapped-array +{ $values + { "path" "a pathname string" } { "c-type" c-type } { "quot" quotation } +} +{ $description "Memory-maps a file for reading and writing as a mapped-array of the given c-type. The mapped file is disposed of when the quotation returns, or if an error is thrown." } +{ $examples + { $unchecked-example + "USING: io.mmap prettyprint specialized-arrays ;" + "SPECIALIZED-ARRAY: uint" +""""resource:license.txt" uint [ + [ . ] each +] with-mapped-array""" + "" + } +} +{ $errors "Throws an error if a memory mapping could not be established." } ; + +HELP: with-mapped-array-reader +{ $values + { "path" "a pathname string" } { "c-type" c-type } { "quot" quotation } +} +{ $description "Memory-maps a file for reading as a mapped-array of the given c-type. The mapped file is disposed of when the quotation returns, or if an error is thrown." } +{ $errors "Throws an error if a memory mapping could not be established." } ; + ARTICLE: "io.mmap.arrays" "Working with memory-mapped data" "The " { $link } " word returns an instance of " { $link mapped-file } ", which doesn't directly support the sequence protocol. Instead, it needs to be wrapped in a specialized array of the appropriate C type:" { $subsections } +"Additionally, files may be opened with two combinators which take a c-type as input:" +{ $subsections with-mapped-array } +{ $subsections with-mapped-array-reader } "The appropriate specialized array type must first be generated with " { $link POSTPONE: SPECIALIZED-ARRAY: } "." $nl "Data can also be read and written from the " { $link mapped-file } " by applying low-level alien words to the " { $slot "address" } " slot. This approach is not recommended, though, since in most cases the compiler will generate efficient code for specialized array usage. See " { $link "reading-writing-memory" } " for a description of low-level memory access primitives." ; @@ -46,10 +80,10 @@ ARTICLE: "io.mmap.examples" "Memory-mapped file examples" "USING: alien.c-types grouping io.mmap sequences" "specialized-arrays ;" "SPECIALIZED-ARRAY: char" "" - "\"mydata.dat\" [" - " char 4 " + "\"mydata.dat\" char [" + " 4 " " [ reverse-here ] change-each" - "] with-mapped-file" + "] with-mapped-array" } "Normalize a file containing packed quadrupes of floats:" { $code @@ -57,17 +91,20 @@ ARTICLE: "io.mmap.examples" "Memory-mapped file examples" "SIMD: float" "SPECIALIZED-ARRAY: float-4" "" - "\"mydata.dat\" [" - " float-4 " + "\"mydata.dat\" float-4 [" " [ normalize ] change-each" - "] with-mapped-file" + "] with-mapped-array" } ; ARTICLE: "io.mmap" "Memory-mapped files" "The " { $vocab-link "io.mmap" } " vocabulary implements support for memory-mapped files." { $subsections } -"Memory-mapped files are disposable and can be closed with " { $link dispose } " or " { $link with-disposal } ". A utility combinator which wraps the above:" +"Memory-mapped files are disposable and can be closed with " { $link dispose } " or " { $link with-disposal } "." $nl +"Utility combinators which wrap the above:" { $subsections with-mapped-file } +{ $subsections with-mapped-file-reader } +{ $subsections with-mapped-array } +{ $subsections with-mapped-array-reader } "Instances of " { $link mapped-file } " don't support any interesting operations in themselves. There are two facilities for accessing their contents:" { $subsections "io.mmap.arrays" diff --git a/basis/io/mmap/mmap.factor b/basis/io/mmap/mmap.factor index 19587cda34..5f35278b05 100644 --- a/basis/io/mmap/mmap.factor +++ b/basis/io/mmap/mmap.factor @@ -8,13 +8,13 @@ IN: io.mmap TUPLE: mapped-file < disposable address handle length ; -HOOK: (mapped-file-reader) os ( path length -- address handle ) -HOOK: (mapped-file-r/w) os ( path length -- address handle ) - ERROR: bad-mmap-size n ; > ] bi @@ -45,6 +45,19 @@ M: mapped-file dispose* ( mmap -- ) close-mapped-file ; : with-mapped-file-reader ( path quot -- ) [ ] dip with-disposal ; inline + ] curry ] dip compose with-disposal ; inline + +PRIVATE> + +: with-mapped-array ( path c-type quot -- ) + [ ] 2dip (with-mapped-array) ; inline + +: with-mapped-array-reader ( path c-type quot -- ) + [ ] 2dip (with-mapped-array) ; inline + { { [ os unix? ] [ "io.mmap.unix" require ] } { [ os winnt? ] [ "io.mmap.windows" require ] } diff --git a/basis/io/mmap/unix/unix.factor b/basis/io/mmap/unix/unix.factor index 7d12d52361..559417d2b9 100644 --- a/basis/io/mmap/unix/unix.factor +++ b/basis/io/mmap/unix/unix.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2007 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. -USING: alien io io.files kernel math math.bitwise system unix -io.backend.unix io.ports io.mmap destructors locals accessors ; +USING: accessors destructors io.backend.unix io.mmap +io.mmap.private kernel locals math.bitwise system unix ; IN: io.mmap.unix :: mmap-open ( path length prot flags open-mode -- alien fd ) diff --git a/basis/io/mmap/windows/windows.factor b/basis/io/mmap/windows/windows.factor index 8fdc7fefd9..a2c1f972a6 100644 --- a/basis/io/mmap/windows/windows.factor +++ b/basis/io/mmap/windows/windows.factor @@ -1,6 +1,6 @@ USING: alien alien.c-types arrays destructors generic io.mmap io.ports io.backend.windows io.files.windows io.backend.windows.privileges -kernel libc math math.bitwise namespaces quotations sequences +io.mmap.private kernel libc math math.bitwise namespaces quotations sequences windows windows.advapi32 windows.kernel32 io.backend system accessors locals windows.errors ; IN: io.mmap.windows From 7403bcef0ce2f0116ed8780de0580f9e09528614 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Thu, 8 Oct 2009 16:58:24 -0500 Subject: [PATCH 40/63] make pngs read scanlines in terms of bits instead of bytes --- basis/compression/inflate/inflate.factor | 6 +-- basis/images/png/png.factor | 47 +++++++++++++++++------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/basis/compression/inflate/inflate.factor b/basis/compression/inflate/inflate.factor index ab27c70ac0..567c435c2e 100644 --- a/basis/compression/inflate/inflate.factor +++ b/basis/compression/inflate/inflate.factor @@ -3,7 +3,7 @@ USING: accessors arrays assocs byte-vectors combinators combinators.smart compression.huffman fry hashtables io.binary kernel literals locals math math.bitwise math.order math.ranges -sequences sorting memoize combinators.short-circuit ; +sequences sorting memoize combinators.short-circuit byte-arrays ; QUALIFIED-WITH: bitstreams bs IN: compression.inflate @@ -88,14 +88,14 @@ CONSTANT: dist-table : nth* ( n seq -- elt ) [ length 1 - swap - ] [ nth ] bi ; inline -:: inflate-lz77 ( seq -- bytes ) +:: inflate-lz77 ( seq -- byte-array ) 1000 :> bytes seq [ dup array? [ first2 '[ _ 1 - bytes nth* bytes push ] times ] [ bytes push ] if ] each - bytes ; + bytes >byte-array ; :: inflate-huffman ( bitstream tables -- bytes ) bitstream tables [ ] with map :> tables diff --git a/basis/images/png/png.factor b/basis/images/png/png.factor index 08d8c56667..74c40d1291 100755 --- a/basis/images/png/png.factor +++ b/basis/images/png/png.factor @@ -4,6 +4,7 @@ USING: accessors arrays checksums checksums.crc32 combinators compression.inflate fry grouping images images.loader io io.binary io.encodings.ascii io.encodings.string kernel locals math math.bitwise math.ranges sequences sorting ; +QUALIFIED-WITH: bitstreams bs IN: images.png SINGLETON: png-image @@ -85,18 +86,17 @@ ERROR: unimplemented-color-type image ; : inflate-data ( loading-png -- bytes ) find-compressed-bytes zlib-inflate ; -: scale-bit-depth ( loading-png -- n ) bit-depth>> 8 / ; inline - -: png-bytes-per-pixel ( loading-png -- n ) - dup color-type>> { - { truecolor [ scale-bit-depth 3 * ] } - { truecolor-alpha [ scale-bit-depth 4 * ] } +: png-components-per-pixel ( loading-png -- n ) + color-type>> { + { truecolor [ 3 ] } + { truecolor-alpha [ 4 ] } [ unknown-color-type ] } case ; inline : png-group-width ( loading-png -- n ) ! 1 + is for the filter type, 1 byte preceding each line - [ png-bytes-per-pixel ] [ width>> ] bi * 1 + ; + [ [ png-components-per-pixel ] [ bit-depth>> ] bi * ] + [ width>> ] bi * 1 + ; :: paeth ( a b c -- p ) a b + c - { a b c } [ [ - abs ] keep 2array ] with map @@ -117,7 +117,7 @@ ERROR: unimplemented-color-type image ; } case curr width tail ; -:: reverse-png-filter ( n lines -- byte-array ) +:: reverse-png-filter ( lines n -- byte-array ) lines dup first length 0 prefix [ n 1 - 0 prepend ] map 2 clump [ @@ -130,17 +130,36 @@ ERROR: unimplemented-color-type image ; ERROR: unimplemented-interlace ; -: reverse-interlace ( byte-array loading-png -- byte-array ) +: reverse-interlace ( byte-array loading-png -- bitstream ) { { interlace-none [ ] } { interlace-adam7 [ unimplemented-interlace ] } [ unimplemented-interlace ] - } case ; + } case bs: ; -: png-image-bytes ( loading-png -- byte-array ) - [ png-bytes-per-pixel ] - [ [ inflate-data ] [ interlace-method>> ] bi reverse-interlace ] - [ png-group-width ] tri group reverse-png-filter ; +: uncompress-bytes ( loading-png -- bitstream ) + [ inflate-data ] [ interlace-method>> ] bi reverse-interlace ; + +:: png-image-bytes ( loading-png -- byte-array ) + loading-png uncompress-bytes :> bs + loading-png width>> :> width + loading-png height>> :> height + loading-png png-components-per-pixel :> #components + loading-png bit-depth>> :> bit-depth + bit-depth :> depth! + #components width * :> count! + + ! Only read up to 8 bits at a time + bit-depth 16 = [ + 8 depth! + count 2 * count! + ] when + + height [ + 8 bs bs:read + count [ depth bs bs:read ] replicate swap prefix + ] replicate + #components bit-depth 16 = [ 2 * ] when reverse-png-filter ; ERROR: unknown-component-type n ; From 77f968fad6fa529086631e1ed9f5b28012764b96 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Thu, 8 Oct 2009 18:18:33 -0500 Subject: [PATCH 41/63] load greyscale png images, refactor some code --- basis/images/png/png.factor | 95 ++++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/basis/images/png/png.factor b/basis/images/png/png.factor index 74c40d1291..469c060776 100755 --- a/basis/images/png/png.factor +++ b/basis/images/png/png.factor @@ -58,7 +58,7 @@ ERROR: bad-checksum ; 4 read = [ bad-checksum ] unless 4 cut-slice [ ascii decode >>type ] [ B{ } like >>data ] bi* - [ over chunks>> push ] + [ over chunks>> push ] [ type>> ] bi "IEND" = [ read-png-chunks ] unless ; @@ -84,11 +84,13 @@ ERROR: unknown-color-type n ; ERROR: unimplemented-color-type image ; : inflate-data ( loading-png -- bytes ) - find-compressed-bytes zlib-inflate ; + find-compressed-bytes zlib-inflate ; : png-components-per-pixel ( loading-png -- n ) color-type>> { + { greyscale [ 1 ] } { truecolor [ 3 ] } + { greyscale-alpha [ 2 ] } { truecolor-alpha [ 4 ] } [ unknown-color-type ] } case ; inline @@ -98,8 +100,8 @@ ERROR: unimplemented-color-type image ; [ [ png-components-per-pixel ] [ bit-depth>> ] bi * ] [ width>> ] bi * 1 + ; -:: paeth ( a b c -- p ) - a b + c - { a b c } [ [ - abs ] keep 2array ] with map +:: paeth ( a b c -- p ) + a b + c - { a b c } [ [ - abs ] keep 2array ] with map sort-keys first second ; :: png-unfilter-line ( width prev curr filter -- curr' ) @@ -114,7 +116,7 @@ ERROR: unimplemented-color-type image ; { filter-up [ [| n | n x nth n b nth + 256 wrap n x set-nth ] each ] } { filter-average [ [| n | n x nth n a nth n b nth + 2/ + 256 wrap n x set-nth ] each ] } { filter-paeth [ [| n | n x nth n a nth n b nth n c nth paeth + 256 wrap n x set-nth ] each ] } - } case + } case curr width tail ; :: reverse-png-filter ( lines n -- byte-array ) @@ -135,12 +137,12 @@ ERROR: unimplemented-interlace ; { interlace-none [ ] } { interlace-adam7 [ unimplemented-interlace ] } [ unimplemented-interlace ] - } case bs: ; + } case bs: ; : uncompress-bytes ( loading-png -- bitstream ) [ inflate-data ] [ interlace-method>> ] bi reverse-interlace ; -:: png-image-bytes ( loading-png -- byte-array ) +:: raw-bytes ( loading-png -- array ) loading-png uncompress-bytes :> bs loading-png width>> :> width loading-png height>> :> height @@ -165,33 +167,41 @@ ERROR: unknown-component-type n ; : png-component ( loading-png -- obj ) bit-depth>> { + { 1 [ ubyte-components ] } + { 2 [ ubyte-components ] } + { 4 [ ubyte-components ] } { 8 [ ubyte-components ] } { 16 [ ushort-components ] } [ unknown-component-type ] } case ; -: loading-png>image ( loading-png -- image ) - [ image new ] dip { - [ png-image-bytes >>bitmap ] - [ [ width>> ] [ height>> ] bi 2array >>dim ] - [ png-component >>component-type ] - } cleave ; +: scale-factor ( n -- n' ) + { + { 1 [ 255 ] } + { 2 [ 127 ] } + { 4 [ 17 ] } + { 8 [ 1 ] } + } case ; -: decode-greyscale ( loading-png -- image ) - unimplemented-color-type ; - -: decode-truecolor ( loading-png -- image ) - loading-png>image RGB >>component-order ; - -: decode-indexed-color ( loading-png -- image ) - unimplemented-color-type ; - -: decode-greyscale-alpha ( loading-png -- image ) - unimplemented-color-type ; - -: decode-truecolor-alpha ( loading-png -- image ) - loading-png>image RGBA >>component-order ; +: scale-greyscale ( byte-array loading-png -- byte-array' ) + [ bit-depth>> ] [ color-type>> ] bi { + { greyscale [ + dup 16 = [ + drop + ] [ + scale-factor '[ _ * ] B{ } map-as + ] if + ] } + { greyscale-alpha [ + [ 8 group ] dip '[ + [ [ 0 5 ] dip [ _ * ] change-each ] keep + ] map B{ } concat-as + ] } + } case ; +: decode-greyscale ( loading-png -- byte-array ) + [ raw-bytes ] keep scale-greyscale ; + ERROR: invalid-color-type/bit-depth loading-png ; : validate-bit-depth ( loading-png seq -- loading-png ) @@ -213,16 +223,33 @@ ERROR: invalid-color-type/bit-depth loading-png ; : validate-truecolor-alpha ( loading-png -- loading-png ) { 8 16 } validate-bit-depth ; -: png>image ( loading-png -- image ) +: loading-png>bitmap ( loading-png -- bytes component-order ) dup color-type>> { - { greyscale [ validate-greyscale decode-greyscale ] } - { truecolor [ validate-truecolor decode-truecolor ] } - { indexed-color [ validate-indexed-color decode-indexed-color ] } - { greyscale-alpha [ validate-greyscale-alpha decode-greyscale-alpha ] } - { truecolor-alpha [ validate-truecolor-alpha decode-truecolor-alpha ] } + { greyscale [ + validate-greyscale decode-greyscale L + ] } + { truecolor [ + validate-truecolor raw-bytes RGB + ] } + { indexed-color [ + validate-indexed-color unimplemented-color-type + ] } + { greyscale-alpha [ + validate-greyscale-alpha decode-greyscale LA + ] } + { truecolor-alpha [ + validate-truecolor-alpha raw-bytes RGBA + ] } [ unknown-color-type ] } case ; +: loading-png>image ( loading-png -- image ) + [ image new ] dip { + [ loading-png>bitmap [ >>bitmap ] [ >>component-order ] bi* ] + [ [ width>> ] [ height>> ] bi 2array >>dim ] + [ png-component >>component-type ] + } cleave ; + : load-png ( stream -- loading-png ) [ @@ -232,4 +259,4 @@ ERROR: invalid-color-type/bit-depth loading-png ; ] with-input-stream ; M: png-image stream>image - drop load-png png>image ; + drop load-png loading-png>image ; From 2945393965491c23d614a43d531639a8f5be4fa4 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Thu, 8 Oct 2009 19:37:14 -0500 Subject: [PATCH 42/63] dont scale 8,16 bit greyscale pngs. greyscale-alpha pngs are 8,16 bit already, so don't scale them either. --- basis/images/png/png.factor | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/basis/images/png/png.factor b/basis/images/png/png.factor index 469c060776..254ec40f51 100755 --- a/basis/images/png/png.factor +++ b/basis/images/png/png.factor @@ -180,24 +180,14 @@ ERROR: unknown-component-type n ; { 1 [ 255 ] } { 2 [ 127 ] } { 4 [ 17 ] } - { 8 [ 1 ] } } case ; : scale-greyscale ( byte-array loading-png -- byte-array' ) - [ bit-depth>> ] [ color-type>> ] bi { - { greyscale [ - dup 16 = [ - drop - ] [ - scale-factor '[ _ * ] B{ } map-as - ] if - ] } - { greyscale-alpha [ - [ 8 group ] dip '[ - [ [ 0 5 ] dip [ _ * ] change-each ] keep - ] map B{ } concat-as - ] } - } case ; + bit-depth>> dup 8 >= [ + drop + ] [ + scale-factor '[ _ * ] B{ } map-as + ] if ; : decode-greyscale ( loading-png -- byte-array ) [ raw-bytes ] keep scale-greyscale ; @@ -235,7 +225,7 @@ ERROR: invalid-color-type/bit-depth loading-png ; validate-indexed-color unimplemented-color-type ] } { greyscale-alpha [ - validate-greyscale-alpha decode-greyscale LA + validate-greyscale-alpha raw-bytes LA ] } { truecolor-alpha [ validate-truecolor-alpha raw-bytes RGBA From fd4c6b73bb0401e3c3138de890569865b1220952 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Thu, 8 Oct 2009 20:33:15 -0500 Subject: [PATCH 43/63] ushort pngs are byte-reversed from how i'm reading them -- fixed. --- basis/images/png/png.factor | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/basis/images/png/png.factor b/basis/images/png/png.factor index 254ec40f51..c41a1956cd 100755 --- a/basis/images/png/png.factor +++ b/basis/images/png/png.factor @@ -3,7 +3,7 @@ USING: accessors arrays checksums checksums.crc32 combinators compression.inflate fry grouping images images.loader io io.binary io.encodings.ascii io.encodings.string kernel locals -math math.bitwise math.ranges sequences sorting ; +math math.bitwise math.ranges sequences sorting assocs ; QUALIFIED-WITH: bitstreams bs IN: images.png @@ -183,11 +183,11 @@ ERROR: unknown-component-type n ; } case ; : scale-greyscale ( byte-array loading-png -- byte-array' ) - bit-depth>> dup 8 >= [ - drop - ] [ - scale-factor '[ _ * ] B{ } map-as - ] if ; + bit-depth>> { + { 8 [ ] } + { 16 [ 2 group [ swap ] assoc-map B{ } concat-as ] } + [ scale-factor '[ _ * ] B{ } map-as ] + } case ; : decode-greyscale ( loading-png -- byte-array ) [ raw-bytes ] keep scale-greyscale ; @@ -213,6 +213,11 @@ ERROR: invalid-color-type/bit-depth loading-png ; : validate-truecolor-alpha ( loading-png -- loading-png ) { 8 16 } validate-bit-depth ; +: decode-greyscale-alpha ( loading-image -- byte-array' ) + [ raw-bytes ] [ bit-depth>> ] bi 16 = [ + 3 group [ first3 swapd 3array ] map B{ } concat-as + ] when ; + : loading-png>bitmap ( loading-png -- bytes component-order ) dup color-type>> { { greyscale [ @@ -225,7 +230,7 @@ ERROR: invalid-color-type/bit-depth loading-png ; validate-indexed-color unimplemented-color-type ] } { greyscale-alpha [ - validate-greyscale-alpha raw-bytes LA + validate-greyscale-alpha decode-greyscale-alpha LA ] } { truecolor-alpha [ validate-truecolor-alpha raw-bytes RGBA From 796b1c8977b26c63f06c4866e99aad32d4657c39 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Thu, 8 Oct 2009 20:37:00 -0500 Subject: [PATCH 44/63] fix byte swapping on greyscale-alpha --- basis/images/png/png.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basis/images/png/png.factor b/basis/images/png/png.factor index c41a1956cd..595bb62ed4 100755 --- a/basis/images/png/png.factor +++ b/basis/images/png/png.factor @@ -215,7 +215,7 @@ ERROR: invalid-color-type/bit-depth loading-png ; : decode-greyscale-alpha ( loading-image -- byte-array' ) [ raw-bytes ] [ bit-depth>> ] bi 16 = [ - 3 group [ first3 swapd 3array ] map B{ } concat-as + 4 group [ first4 [ swap ] 2dip 4array ] map B{ } concat-as ] when ; : loading-png>bitmap ( loading-png -- bytes component-order ) From 8556476b76aabbcc84dcbf9a7709cbacd958595f Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Thu, 8 Oct 2009 20:55:53 -0500 Subject: [PATCH 45/63] handle indexed color pngs --- basis/images/png/png.factor | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/basis/images/png/png.factor b/basis/images/png/png.factor index 595bb62ed4..5ac3ee7103 100755 --- a/basis/images/png/png.factor +++ b/basis/images/png/png.factor @@ -3,7 +3,8 @@ USING: accessors arrays checksums checksums.crc32 combinators compression.inflate fry grouping images images.loader io io.binary io.encodings.ascii io.encodings.string kernel locals -math math.bitwise math.ranges sequences sorting assocs ; +math math.bitwise math.ranges sequences sorting assocs +math.functions ; QUALIFIED-WITH: bitstreams bs IN: images.png @@ -65,6 +66,9 @@ ERROR: bad-checksum ; : find-chunk ( loading-png string -- chunk ) [ chunks>> ] dip '[ type>> _ = ] find nip ; +: find-chunks ( loading-png string -- chunk ) + [ chunks>> ] dip '[ type>> _ = ] filter ; + : parse-ihdr-chunk ( loading-png -- loading-png ) dup "IHDR" find-chunk data>> { [ [ 0 4 ] dip subseq be> >>width ] @@ -77,8 +81,7 @@ ERROR: bad-checksum ; } cleave ; : find-compressed-bytes ( loading-png -- bytes ) - chunks>> [ type>> "IDAT" = ] filter - [ data>> ] map concat ; + "IDAT" find-chunks [ data>> ] map concat ; ERROR: unknown-color-type n ; ERROR: unimplemented-color-type image ; @@ -91,6 +94,7 @@ ERROR: unimplemented-color-type image ; { greyscale [ 1 ] } { truecolor [ 3 ] } { greyscale-alpha [ 2 ] } + { indexed-color [ 1 ] } { truecolor-alpha [ 4 ] } [ unknown-color-type ] } case ; inline @@ -160,6 +164,7 @@ ERROR: unimplemented-interlace ; height [ 8 bs bs:read count [ depth bs bs:read ] replicate swap prefix + 8 bs bs:align ] replicate #components bit-depth 16 = [ 2 * ] when reverse-png-filter ; @@ -191,6 +196,20 @@ ERROR: unknown-component-type n ; : decode-greyscale ( loading-png -- byte-array ) [ raw-bytes ] keep scale-greyscale ; + +: decode-greyscale-alpha ( loading-image -- byte-array ) + [ raw-bytes ] [ bit-depth>> ] bi 16 = [ + 4 group [ first4 [ swap ] 2dip 4array ] map B{ } concat-as + ] when ; + +ERROR: invalid-PLTE array ; + +: verify-PLTE ( seq -- seq ) + dup length 3 divisor? [ invalid-PLTE ] unless ; + +: decode-indexed-color ( loading-image -- byte-array ) + [ raw-bytes ] keep "PLTE" find-chunk data>> verify-PLTE + 3 group '[ _ nth ] { } map-as B{ } concat-as ; inline ERROR: invalid-color-type/bit-depth loading-png ; @@ -213,11 +232,6 @@ ERROR: invalid-color-type/bit-depth loading-png ; : validate-truecolor-alpha ( loading-png -- loading-png ) { 8 16 } validate-bit-depth ; -: decode-greyscale-alpha ( loading-image -- byte-array' ) - [ raw-bytes ] [ bit-depth>> ] bi 16 = [ - 4 group [ first4 [ swap ] 2dip 4array ] map B{ } concat-as - ] when ; - : loading-png>bitmap ( loading-png -- bytes component-order ) dup color-type>> { { greyscale [ @@ -227,7 +241,7 @@ ERROR: invalid-color-type/bit-depth loading-png ; validate-truecolor raw-bytes RGB ] } { indexed-color [ - validate-indexed-color unimplemented-color-type + validate-indexed-color decode-indexed-color RGB ] } { greyscale-alpha [ validate-greyscale-alpha decode-greyscale-alpha LA From 36775661a94d873d3963e368260aa219405a0275 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Thu, 8 Oct 2009 21:37:30 -0500 Subject: [PATCH 46/63] fix unit test --- basis/compression/inflate/inflate-tests.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basis/compression/inflate/inflate-tests.factor b/basis/compression/inflate/inflate-tests.factor index e2beefb9b2..7bda94a999 100644 --- a/basis/compression/inflate/inflate-tests.factor +++ b/basis/compression/inflate/inflate-tests.factor @@ -4,7 +4,7 @@ USING: tools.test compression.inflate ; IN: compression.inflate.tests [ -BV{ +B{ 1 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 122 121 94 119 239 237 227 88 16 16 10 5 16 17 26 172 3 20 19 245 22 54 55 From 7d39e51d9a2d80fed7dac815e1b85f8e51370f3b Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Thu, 8 Oct 2009 23:06:40 -0500 Subject: [PATCH 47/63] add using and unit tests for mmap --- basis/io/mmap/mmap-docs.factor | 2 +- basis/io/mmap/mmap-tests.factor | 21 +++++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/basis/io/mmap/mmap-docs.factor b/basis/io/mmap/mmap-docs.factor index 3379a2879b..fe16e08467 100644 --- a/basis/io/mmap/mmap-docs.factor +++ b/basis/io/mmap/mmap-docs.factor @@ -47,7 +47,7 @@ HELP: with-mapped-array { $description "Memory-maps a file for reading and writing as a mapped-array of the given c-type. The mapped file is disposed of when the quotation returns, or if an error is thrown." } { $examples { $unchecked-example - "USING: io.mmap prettyprint specialized-arrays ;" + "USING: alien.c-types io.mmap prettyprint specialized-arrays ;" "SPECIALIZED-ARRAY: uint" """"resource:license.txt" uint [ [ . ] each diff --git a/basis/io/mmap/mmap-tests.factor b/basis/io/mmap/mmap-tests.factor index 3ed3447603..94f8c77883 100644 --- a/basis/io/mmap/mmap-tests.factor +++ b/basis/io/mmap/mmap-tests.factor @@ -1,7 +1,7 @@ -USING: io io.mmap io.files io.files.temp io.directories kernel -tools.test continuations sequences io.encodings.ascii accessors -math compiler.tree.debugger alien.data alien.c-types -sequences.private ; +USING: alien.c-types alien.data compiler.tree.debugger +continuations io.directories io.encodings.ascii io.files +io.files.temp io.mmap kernel math sequences sequences.private +specialized-arrays specialized-arrays.instances.uint tools.test ; IN: io.mmap.tests [ "mmap-test-file.txt" temp-file delete-file ] ignore-errors @@ -10,6 +10,19 @@ IN: io.mmap.tests [ 5 ] [ "mmap-test-file.txt" temp-file [ char length ] with-mapped-file ] unit-test [ 5 ] [ "mmap-test-file.txt" temp-file [ char length ] with-mapped-file-reader ] unit-test [ "22345" ] [ "mmap-test-file.txt" temp-file ascii file-contents ] unit-test + +SPECIALIZED-ARRAY: uint + +[ t ] [ + "mmap-test-file.txt" temp-file uint [ sum ] with-mapped-array + integer? +] unit-test + +[ t ] [ + "mmap-test-file.txt" temp-file uint [ sum ] with-mapped-array-reader + integer? +] unit-test + [ "mmap-test-file.txt" temp-file delete-file ] ignore-errors From 21f55ab1a3beb35232d7623d6084b67f31fb087a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 8 Oct 2009 23:10:32 -0500 Subject: [PATCH 48/63] vm: more efficient code heap remembered set --- vm/aging_collector.cpp | 5 +++-- vm/code_heap.cpp | 8 ++++---- vm/code_heap.hpp | 12 +++++------- vm/collector.hpp | 2 ++ vm/copying_collector.hpp | 23 ++++++----------------- vm/full_collector.cpp | 4 +--- vm/gc.cpp | 29 ++++++----------------------- vm/nursery_collector.cpp | 6 +++--- vm/to_tenured_collector.cpp | 8 +++++--- vm/vm.hpp | 2 +- 10 files changed, 36 insertions(+), 63 deletions(-) diff --git a/vm/aging_collector.cpp b/vm/aging_collector.cpp index 287e5c306c..9b69cd2977 100644 --- a/vm/aging_collector.cpp +++ b/vm/aging_collector.cpp @@ -17,11 +17,12 @@ void factor_vm::collect_aging() collector.trace_roots(); collector.trace_contexts(); collector.trace_cards(data->tenured); - collector.trace_code_heap_roots(); + collector.trace_code_heap_roots(&code->points_to_aging); collector.cheneys_algorithm(); - update_dirty_code_blocks(); + update_dirty_code_blocks(&code->points_to_aging); nursery.here = nursery.start; + code->points_to_nursery.clear(); } } diff --git a/vm/code_heap.cpp b/vm/code_heap.cpp index 6a5391a589..0cb2cae50f 100755 --- a/vm/code_heap.cpp +++ b/vm/code_heap.cpp @@ -7,8 +7,8 @@ code_heap::code_heap(bool secure_gc, cell size) : heap(secure_gc,size) {} void code_heap::write_barrier(code_block *compiled) { - remembered_set[compiled] = nursery_gen; - youngest_referenced_generation = nursery_gen; + points_to_nursery.insert(compiled); + points_to_aging.insert(compiled); } bool code_heap::needs_fixup_p(code_block *compiled) @@ -18,7 +18,8 @@ bool code_heap::needs_fixup_p(code_block *compiled) void code_heap::code_heap_free(code_block *compiled) { - remembered_set.erase(compiled); + points_to_nursery.erase(compiled); + points_to_aging.erase(compiled); needs_fixup.erase(compiled); heap_free(compiled); } @@ -27,7 +28,6 @@ void code_heap::code_heap_free(code_block *compiled) void factor_vm::init_code_heap(cell size) { code = new code_heap(secure_gc,size); - code->youngest_referenced_generation = nursery_gen; } bool factor_vm::in_code_heap_p(cell ptr) diff --git a/vm/code_heap.hpp b/vm/code_heap.hpp index feea7da307..589336fad5 100755 --- a/vm/code_heap.hpp +++ b/vm/code_heap.hpp @@ -4,14 +4,12 @@ namespace factor struct code_heap : heap { /* Set of blocks which need full relocation. */ unordered_set needs_fixup; - - /* Maps code blocks to the youngest generation containing - one of their literals. If this is tenured (0), the code block - is not part of the remembered set. */ - unordered_map remembered_set; - /* Minimum value in the above map. */ - cell youngest_referenced_generation; + /* Code blocks which may reference objects in the nursery */ + std::set points_to_nursery; + + /* Code blocks which may reference objects in aging space or the nursery */ + std::set points_to_aging; explicit code_heap(bool secure_gc, cell size); void write_barrier(code_block *compiled); diff --git a/vm/collector.hpp b/vm/collector.hpp index 06134dd9b7..bfe113c706 100644 --- a/vm/collector.hpp +++ b/vm/collector.hpp @@ -4,6 +4,7 @@ namespace factor template struct collector { factor_vm *myvm; data_heap *data; + code_heap *code; gc_state *current_gc; TargetGeneration *target; Policy policy; @@ -11,6 +12,7 @@ template struct collector { explicit collector(factor_vm *myvm_, TargetGeneration *target_, Policy policy_) : myvm(myvm_), data(myvm_->data), + code(myvm_->code), current_gc(myvm_->current_gc), target(target_), policy(policy_) {} diff --git a/vm/copying_collector.hpp b/vm/copying_collector.hpp index bb17f2e70d..11465a0de7 100644 --- a/vm/copying_collector.hpp +++ b/vm/copying_collector.hpp @@ -130,24 +130,13 @@ struct copying_collector : collector { this->trace_handle(&compiled->literals); this->trace_handle(&compiled->relocation); } - - /* Trace literals referenced from all code blocks. Only for aging and nursery collections */ - void trace_code_heap_roots() + + void trace_code_heap_roots(std::set *remembered_set) { - if(this->current_gc->collecting_gen >= this->myvm->code->youngest_referenced_generation) - { - unordered_map &remembered_set = this->myvm->code->remembered_set; - unordered_map::const_iterator iter = remembered_set.begin(); - unordered_map::const_iterator end = remembered_set.end(); - - for(; iter != end; iter++) - { - if(this->current_gc->collecting_gen >= iter->second) - trace_literal_references(iter->first); - } - - this->myvm->gc_stats.code_heap_scans++; - } + std::set::const_iterator iter = remembered_set->begin(); + std::set::const_iterator end = remembered_set->end(); + + for(; iter != end; iter++) trace_literal_references(*iter); } void cheneys_algorithm() diff --git a/vm/full_collector.cpp b/vm/full_collector.cpp index c54dd6b72e..15a76590f1 100644 --- a/vm/full_collector.cpp +++ b/vm/full_collector.cpp @@ -78,9 +78,7 @@ void full_collector::trace_literal_references(code_block *compiled) collections */ void full_collector::mark_code_block(code_block *compiled) { - myvm->check_code_address((cell)compiled); - - this->myvm->code->mark_block(compiled); + this->code->mark_block(compiled); trace_literal_references(compiled); } diff --git a/vm/gc.cpp b/vm/gc.cpp index be31636eb7..795b75f149 100755 --- a/vm/gc.cpp +++ b/vm/gc.cpp @@ -29,34 +29,17 @@ void factor_vm::free_unmarked_code_blocks() { literal_and_word_reference_updater updater(this); code->free_unmarked(updater); - code->remembered_set.clear(); - code->youngest_referenced_generation = tenured_gen; + code->points_to_nursery.clear(); + code->points_to_aging.clear(); } -void factor_vm::update_dirty_code_blocks() +void factor_vm::update_dirty_code_blocks(std::set *remembered_set) { /* The youngest generation that any code block can now reference */ - cell gen; + std::set::iterator iter = remembered_set->begin(); + std::set::iterator end = remembered_set->end(); - if(current_gc->collecting_accumulation_gen_p()) - gen = current_gc->collecting_gen; - else - gen = current_gc->collecting_gen + 1; - - unordered_map::iterator iter = code->remembered_set.begin(); - unordered_map::iterator end = code->remembered_set.end(); - - for(; iter != end; iter++) - { - if(current_gc->collecting_gen >= iter->second) - { - check_code_address((cell)iter->first); - update_literal_references(iter->first); - iter->second = gen; - } - } - - code->youngest_referenced_generation = gen; + for(; iter != end; iter++) update_literal_references(*iter); } void factor_vm::record_gc_stats() diff --git a/vm/nursery_collector.cpp b/vm/nursery_collector.cpp index f5dc386053..cff753e687 100644 --- a/vm/nursery_collector.cpp +++ b/vm/nursery_collector.cpp @@ -15,12 +15,12 @@ void factor_vm::collect_nursery() collector.trace_contexts(); collector.trace_cards(data->tenured); collector.trace_cards(data->aging); - collector.trace_code_heap_roots(); + collector.trace_code_heap_roots(&code->points_to_nursery); collector.cheneys_algorithm(); - - update_dirty_code_blocks(); + update_dirty_code_blocks(&code->points_to_nursery); nursery.here = nursery.start; + code->points_to_nursery.clear(); } } diff --git a/vm/to_tenured_collector.cpp b/vm/to_tenured_collector.cpp index a0341ec93d..1242acd897 100644 --- a/vm/to_tenured_collector.cpp +++ b/vm/to_tenured_collector.cpp @@ -14,12 +14,14 @@ void factor_vm::collect_to_tenured() collector.trace_roots(); collector.trace_contexts(); collector.trace_cards(data->tenured); - collector.trace_code_heap_roots(); + collector.trace_code_heap_roots(&code->points_to_aging); collector.cheneys_algorithm(); - update_dirty_code_blocks(); + update_dirty_code_blocks(&code->points_to_aging); - reset_generation(data->aging); nursery.here = nursery.start; + reset_generation(data->aging); + code->points_to_nursery.clear(); + code->points_to_aging.clear(); } } diff --git a/vm/vm.hpp b/vm/vm.hpp index 80dd67c76d..2957714d42 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -264,7 +264,7 @@ struct factor_vm // gc void free_unmarked_code_blocks(); - void update_dirty_code_blocks(); + void update_dirty_code_blocks(std::set *remembered_set); void collect_nursery(); void collect_aging(); void collect_to_tenured(); From cb2673a6f526c76fea13875e4553ec009058cc64 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 8 Oct 2009 23:39:54 -0500 Subject: [PATCH 49/63] vm: cleanup --- vm/copying_collector.hpp | 17 ++++++++--------- vm/gc.cpp | 6 +++--- vm/gc.hpp | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/vm/copying_collector.hpp b/vm/copying_collector.hpp index 11465a0de7..9e16753660 100644 --- a/vm/copying_collector.hpp +++ b/vm/copying_collector.hpp @@ -17,7 +17,7 @@ struct copying_collector : collector { } } - template void trace_card(SourceGeneration *gen, card *ptr) + template void trace_card(SourceGeneration *gen, card *ptr, card unmask) { cell card_start = this->myvm->card_to_addr(ptr); cell card_scan = card_start + gen->card_offset(card_start); @@ -25,6 +25,8 @@ struct copying_collector : collector { trace_objects_between(gen,card_scan,&card_end); + *ptr &= ~unmask; + this->myvm->gc_stats.cards_scanned++; } @@ -42,14 +44,10 @@ struct copying_collector : collector { { card *ptr = (card *)quad_ptr; - for(int card = 0; card < 4; card++) - { - if(ptr[card] & mask) - { - trace_card(gen,&ptr[card]); - ptr[card] &= ~unmask; - } - } + if(ptr[0] & mask) trace_card(gen,&ptr[0],unmask); + if(ptr[1] & mask) trace_card(gen,&ptr[1],unmask); + if(ptr[2] & mask) trace_card(gen,&ptr[2],unmask); + if(ptr[3] & mask) trace_card(gen,&ptr[3],unmask); } } @@ -129,6 +127,7 @@ struct copying_collector : collector { this->trace_handle(&compiled->owner); this->trace_handle(&compiled->literals); this->trace_handle(&compiled->relocation); + this->myvm->gc_stats.code_blocks_scanned++; } void trace_code_heap_roots(std::set *remembered_set) diff --git a/vm/gc.cpp b/vm/gc.cpp index 795b75f149..a435e5f465 100755 --- a/vm/gc.cpp +++ b/vm/gc.cpp @@ -36,8 +36,8 @@ void factor_vm::free_unmarked_code_blocks() void factor_vm::update_dirty_code_blocks(std::set *remembered_set) { /* The youngest generation that any code block can now reference */ - std::set::iterator iter = remembered_set->begin(); - std::set::iterator end = remembered_set->end(); + std::set::const_iterator iter = remembered_set->begin(); + std::set::const_iterator end = remembered_set->end(); for(; iter != end; iter++) update_literal_references(*iter); } @@ -146,7 +146,7 @@ void factor_vm::primitive_gc_stats() result.add(tag(ulong_long_to_bignum(gc_stats.cards_scanned))); result.add(tag(ulong_long_to_bignum(gc_stats.decks_scanned))); result.add(tag(ulong_long_to_bignum(gc_stats.card_scan_time))); - result.add(allot_cell(gc_stats.code_heap_scans)); + result.add(allot_cell(gc_stats.code_blocks_scanned)); result.trim(); dpush(result.elements.value()); diff --git a/vm/gc.hpp b/vm/gc.hpp index 9304a3ad03..d95d8df833 100755 --- a/vm/gc.hpp +++ b/vm/gc.hpp @@ -15,7 +15,7 @@ struct gc_statistics { u64 cards_scanned; u64 decks_scanned; u64 card_scan_time; - cell code_heap_scans; + u64 code_blocks_scanned; }; struct gc_state { From 6e4b4d583037a942208c377de296100c483f98fd Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 8 Oct 2009 23:58:20 -0500 Subject: [PATCH 50/63] Fix problem if last card is marked --- vm/old_space.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/old_space.cpp b/vm/old_space.cpp index 572f1edc14..7dcd33f533 100644 --- a/vm/old_space.cpp +++ b/vm/old_space.cpp @@ -45,7 +45,7 @@ void old_space::clear_allot_markers() cell old_space::next_object_after(factor_vm *myvm, cell scan) { cell size = myvm->untagged_object_size((object *)scan); - if(scan + size < end) + if(scan + size < here) return scan + size; else return NULL; From 4a8be006f08101b2300cef50966cf9ea92839d48 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Fri, 9 Oct 2009 01:25:20 -0500 Subject: [PATCH 51/63] extra error checking in images.png --- basis/images/png/png.factor | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/basis/images/png/png.factor b/basis/images/png/png.factor index 5ac3ee7103..6ebc0f9147 100755 --- a/basis/images/png/png.factor +++ b/basis/images/png/png.factor @@ -4,7 +4,7 @@ USING: accessors arrays checksums checksums.crc32 combinators compression.inflate fry grouping images images.loader io io.binary io.encodings.ascii io.encodings.string kernel locals math math.bitwise math.ranges sequences sorting assocs -math.functions ; +math.functions math.order ; QUALIFIED-WITH: bitstreams bs IN: images.png @@ -146,6 +146,8 @@ ERROR: unimplemented-interlace ; : uncompress-bytes ( loading-png -- bitstream ) [ inflate-data ] [ interlace-method>> ] bi reverse-interlace ; +ERROR: bad-filter n ; + :: raw-bytes ( loading-png -- array ) loading-png uncompress-bytes :> bs loading-png width>> :> width @@ -162,7 +164,7 @@ ERROR: unimplemented-interlace ; ] when height [ - 8 bs bs:read + 8 bs bs:read dup 0 4 between? [ bad-filter ] unless count [ depth bs bs:read ] replicate swap prefix 8 bs bs:align ] replicate @@ -210,7 +212,7 @@ ERROR: invalid-PLTE array ; : decode-indexed-color ( loading-image -- byte-array ) [ raw-bytes ] keep "PLTE" find-chunk data>> verify-PLTE 3 group '[ _ nth ] { } map-as B{ } concat-as ; inline - + ERROR: invalid-color-type/bit-depth loading-png ; : validate-bit-depth ( loading-png seq -- loading-png ) From d34c7854cdd387034b639b3347f4fd2d87abf26f Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 01:37:45 -0500 Subject: [PATCH 52/63] vm: simplify card marking logic, and unmark more cards during aging collections by checking if they actually contained young pointers or not --- vm/aging_collector.cpp | 4 +- vm/code_heap.hpp | 2 +- vm/collector.hpp | 16 ++++-- vm/copying_collector.hpp | 110 +++++++++++++++--------------------- vm/master.hpp | 4 -- vm/nursery_collector.cpp | 8 ++- vm/to_tenured_collector.cpp | 4 +- 7 files changed, 70 insertions(+), 78 deletions(-) diff --git a/vm/aging_collector.cpp b/vm/aging_collector.cpp index 9b69cd2977..6867ea3083 100644 --- a/vm/aging_collector.cpp +++ b/vm/aging_collector.cpp @@ -16,7 +16,9 @@ void factor_vm::collect_aging() collector.trace_roots(); collector.trace_contexts(); - collector.trace_cards(data->tenured); + collector.trace_cards(data->tenured, + card_points_to_aging, + complex_unmarker(card_mark_mask,card_points_to_nursery)); collector.trace_code_heap_roots(&code->points_to_aging); collector.cheneys_algorithm(); update_dirty_code_blocks(&code->points_to_aging); diff --git a/vm/code_heap.hpp b/vm/code_heap.hpp index 589336fad5..f9084d0b43 100755 --- a/vm/code_heap.hpp +++ b/vm/code_heap.hpp @@ -3,7 +3,7 @@ namespace factor struct code_heap : heap { /* Set of blocks which need full relocation. */ - unordered_set needs_fixup; + std::set needs_fixup; /* Code blocks which may reference objects in the nursery */ std::set points_to_nursery; diff --git a/vm/collector.hpp b/vm/collector.hpp index bfe113c706..2f1c34bd8c 100644 --- a/vm/collector.hpp +++ b/vm/collector.hpp @@ -30,15 +30,15 @@ template struct collector { return untagged; } - void trace_handle(cell *handle) + bool trace_handle(cell *handle) { cell pointer = *handle; - if(immediate_p(pointer)) return; + if(immediate_p(pointer)) return false; object *untagged = myvm->untag(pointer); if(!policy.should_copy_p(untagged)) - return; + return false; object *forwarding = resolve_forwarding(untagged); @@ -50,18 +50,24 @@ template struct collector { untagged = forwarding; *handle = RETAG(untagged,TAG(pointer)); + + return true; } - void trace_slots(object *ptr) + bool trace_slots(object *ptr) { cell *slot = (cell *)ptr; cell *end = (cell *)((cell)ptr + myvm->binary_payload_start(ptr)); + bool copied = false; + if(slot != end) { slot++; - for(; slot < end; slot++) trace_handle(slot); + for(; slot < end; slot++) copied |= trace_handle(slot); } + + return copied; } object *promote_object(object *untagged) diff --git a/vm/copying_collector.hpp b/vm/copying_collector.hpp index 9e16753660..b8b63c4bcc 100644 --- a/vm/copying_collector.hpp +++ b/vm/copying_collector.hpp @@ -1,6 +1,26 @@ namespace factor { +struct dummy_unmarker { + void operator()(bool result, card *ptr) {} +}; + +struct simple_unmarker { + card unmask; + simple_unmarker(card unmask_) : unmask(unmask_) {} + void operator()(bool result, card *ptr) { *ptr &= ~unmask; } +}; + +struct complex_unmarker { + card unmask_none, unmask_some; + complex_unmarker(card unmask_none_, card unmask_some_) : + unmask_none(unmask_none_), unmask_some(unmask_some_) {} + + void operator()(bool result, card *ptr) { + *ptr &= (result ? ~unmask_some : ~unmask_none); + } +}; + template struct copying_collector : collector { cell scan; @@ -8,29 +28,37 @@ struct copying_collector : collector { explicit copying_collector(factor_vm *myvm_, TargetGeneration *target_, Policy policy_) : collector(myvm_,target_,policy_), scan(target_->here) {} - template void trace_objects_between(SourceGeneration *gen, cell scan, cell *end) + template + bool trace_objects_between(SourceGeneration *gen, cell scan, cell *end) { + bool copied = false; + while(scan && scan < *end) { - this->trace_slots((object *)scan); + copied |= this->trace_slots((object *)scan); scan = gen->next_object_after(this->myvm,scan); } + + return copied; } - template void trace_card(SourceGeneration *gen, card *ptr, card unmask) + template + bool trace_card(SourceGeneration *gen, card *ptr, Unmarker unmarker) { cell card_start = this->myvm->card_to_addr(ptr); cell card_scan = card_start + gen->card_offset(card_start); cell card_end = this->myvm->card_to_addr(ptr + 1); - trace_objects_between(gen,card_scan,&card_end); - - *ptr &= ~unmask; + bool result = this->trace_objects_between(gen,card_scan,&card_end); + unmarker(result,ptr); this->myvm->gc_stats.cards_scanned++; + + return result; } - template void trace_card_deck(SourceGeneration *gen, card_deck *deck, card mask, card unmask) + template + bool trace_card_deck(SourceGeneration *gen, card_deck *deck, card mask, Unmarker unmarker) { card *first_card = this->myvm->deck_to_card(deck); card *last_card = this->myvm->deck_to_card(deck + 1); @@ -38,84 +66,38 @@ struct copying_collector : collector { u32 *quad_ptr; u32 quad_mask = mask | (mask << 8) | (mask << 16) | (mask << 24); + bool copied = false; + for(quad_ptr = (u32 *)first_card; quad_ptr < (u32 *)last_card; quad_ptr++) { if(*quad_ptr & quad_mask) { card *ptr = (card *)quad_ptr; - if(ptr[0] & mask) trace_card(gen,&ptr[0],unmask); - if(ptr[1] & mask) trace_card(gen,&ptr[1],unmask); - if(ptr[2] & mask) trace_card(gen,&ptr[2],unmask); - if(ptr[3] & mask) trace_card(gen,&ptr[3],unmask); + if(ptr[0] & mask) copied |= trace_card(gen,&ptr[0],unmarker); + if(ptr[1] & mask) copied |= trace_card(gen,&ptr[1],unmarker); + if(ptr[2] & mask) copied |= trace_card(gen,&ptr[2],unmarker); + if(ptr[3] & mask) copied |= trace_card(gen,&ptr[3],unmarker); } } this->myvm->gc_stats.decks_scanned++; + + return copied; } - template void trace_cards(SourceGeneration *gen) + template + void trace_cards(SourceGeneration *gen, cell mask, Unmarker unmarker) { u64 start = current_micros(); card_deck *first_deck = this->myvm->addr_to_deck(gen->start); card_deck *last_deck = this->myvm->addr_to_deck(gen->end); - card mask, unmask; - - /* if we are collecting the nursery, we care about old->nursery pointers - but not old->aging pointers */ - if(this->current_gc->collecting_nursery_p()) - { - mask = card_points_to_nursery; - - /* after the collection, no old->nursery pointers remain - anywhere, but old->aging pointers might remain in tenured - space */ - if(gen->is_tenured_p()) - unmask = card_points_to_nursery; - /* after the collection, all cards in aging space can be - cleared */ - else if(gen->is_aging_p()) - unmask = card_mark_mask; - else - { - critical_error("bug in trace_gen_cards",0); - return; - } - } - /* if we are collecting aging space into tenured space, we care about - all old->nursery and old->aging pointers. no old->aging pointers can - remain */ - else if(this->current_gc->collecting_aging_p()) - { - if(this->current_gc->collecting_aging_again) - { - mask = card_points_to_aging; - unmask = card_mark_mask; - } - /* after we collect aging space into the aging semispace, no - old->nursery pointers remain but tenured space might still have - pointers to aging space. */ - else - { - mask = card_points_to_aging; - unmask = card_points_to_nursery; - } - } - else - { - critical_error("bug in trace_gen_cards",0); - return; - } - for(card_deck *ptr = first_deck; ptr < last_deck; ptr++) { if(*ptr & mask) - { - trace_card_deck(gen,ptr,mask,unmask); - *ptr &= ~unmask; - } + unmarker(trace_card_deck(gen,ptr,mask,unmarker),ptr); } this->myvm->gc_stats.card_scan_time += (current_micros() - start); diff --git a/vm/master.hpp b/vm/master.hpp index fbafaf2d7b..2058af8c43 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -30,21 +30,17 @@ #if __GNUC__ == 4 #include - #include namespace factor { using std::tr1::unordered_map; - using std::tr1::unordered_set; } #elif __GNUC__ == 3 #include - #include namespace factor { using boost::unordered_map; - using boost::unordered_set; } #else #error Factor requires GCC 3.x or later diff --git a/vm/nursery_collector.cpp b/vm/nursery_collector.cpp index cff753e687..de5eab4593 100644 --- a/vm/nursery_collector.cpp +++ b/vm/nursery_collector.cpp @@ -13,8 +13,12 @@ void factor_vm::collect_nursery() collector.trace_roots(); collector.trace_contexts(); - collector.trace_cards(data->tenured); - collector.trace_cards(data->aging); + collector.trace_cards(data->tenured, + card_points_to_nursery, + simple_unmarker(card_points_to_nursery)); + collector.trace_cards(data->aging, + card_points_to_nursery, + simple_unmarker(card_mark_mask)); collector.trace_code_heap_roots(&code->points_to_nursery); collector.cheneys_algorithm(); update_dirty_code_blocks(&code->points_to_nursery); diff --git a/vm/to_tenured_collector.cpp b/vm/to_tenured_collector.cpp index 1242acd897..881b45fbc4 100644 --- a/vm/to_tenured_collector.cpp +++ b/vm/to_tenured_collector.cpp @@ -13,7 +13,9 @@ void factor_vm::collect_to_tenured() collector.trace_roots(); collector.trace_contexts(); - collector.trace_cards(data->tenured); + collector.trace_cards(data->tenured, + card_points_to_aging, + dummy_unmarker()); collector.trace_code_heap_roots(&code->points_to_aging); collector.cheneys_algorithm(); update_dirty_code_blocks(&code->points_to_aging); From f6d4551da5ba649e593c7d6203058be26c4dfbe9 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 02:05:31 -0500 Subject: [PATCH 53/63] vm: remove unrolled card scan loop since it appears to be a performance loss --- vm/copying_collector.hpp | 26 +++++--------------------- vm/old_space.hpp | 7 ++++++- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/vm/copying_collector.hpp b/vm/copying_collector.hpp index b8b63c4bcc..c2a3269f3b 100644 --- a/vm/copying_collector.hpp +++ b/vm/copying_collector.hpp @@ -46,7 +46,7 @@ struct copying_collector : collector { bool trace_card(SourceGeneration *gen, card *ptr, Unmarker unmarker) { cell card_start = this->myvm->card_to_addr(ptr); - cell card_scan = card_start + gen->card_offset(card_start); + cell card_scan = card_start + gen->first_object_in_card(card_start); cell card_end = this->myvm->card_to_addr(ptr + 1); bool result = this->trace_objects_between(gen,card_scan,&card_end); @@ -63,23 +63,10 @@ struct copying_collector : collector { card *first_card = this->myvm->deck_to_card(deck); card *last_card = this->myvm->deck_to_card(deck + 1); - u32 *quad_ptr; - u32 quad_mask = mask | (mask << 8) | (mask << 16) | (mask << 24); - bool copied = false; - for(quad_ptr = (u32 *)first_card; quad_ptr < (u32 *)last_card; quad_ptr++) - { - if(*quad_ptr & quad_mask) - { - card *ptr = (card *)quad_ptr; - - if(ptr[0] & mask) copied |= trace_card(gen,&ptr[0],unmarker); - if(ptr[1] & mask) copied |= trace_card(gen,&ptr[1],unmarker); - if(ptr[2] & mask) copied |= trace_card(gen,&ptr[2],unmarker); - if(ptr[3] & mask) copied |= trace_card(gen,&ptr[3],unmarker); - } - } + for(card *ptr = first_card; ptr < last_card; ptr++) + if(*ptr & mask) copied |= trace_card(gen,ptr,unmarker); this->myvm->gc_stats.decks_scanned++; @@ -87,7 +74,7 @@ struct copying_collector : collector { } template - void trace_cards(SourceGeneration *gen, cell mask, Unmarker unmarker) + void trace_cards(SourceGeneration *gen, card mask, Unmarker unmarker) { u64 start = current_micros(); @@ -95,10 +82,7 @@ struct copying_collector : collector { card_deck *last_deck = this->myvm->addr_to_deck(gen->end); for(card_deck *ptr = first_deck; ptr < last_deck; ptr++) - { - if(*ptr & mask) - unmarker(trace_card_deck(gen,ptr,mask,unmarker),ptr); - } + if(*ptr & mask) unmarker(trace_card_deck(gen,ptr,mask,unmarker),ptr); this->myvm->gc_stats.card_scan_time += (current_micros() - start); } diff --git a/vm/old_space.hpp b/vm/old_space.hpp index 3f70403400..abaad00432 100644 --- a/vm/old_space.hpp +++ b/vm/old_space.hpp @@ -1,6 +1,11 @@ namespace factor { +struct allot_marker { + char first_object_start; + char last_object_start; +}; + struct old_space : zone { card *allot_markers; card *allot_markers_end; @@ -8,7 +13,7 @@ struct old_space : zone { old_space(cell size_, cell start_); ~old_space(); - cell card_offset(cell address) + cell first_object_in_card(cell address) { return allot_markers[(address - start) >> card_bits]; } From 07deeb407c5e33a99a15f1398a5e0bc61d6daa87 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 02:57:04 -0500 Subject: [PATCH 54/63] vm: fix formatting --- vm/gc.cpp | 55 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/vm/gc.cpp b/vm/gc.cpp index a435e5f465..3850dc642e 100755 --- a/vm/gc.cpp +++ b/vm/gc.cpp @@ -67,36 +67,37 @@ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_ /* Keep trying to GC higher and higher generations until we don't run out of space */ - if(setjmp(current_gc->gc_unwind)) - { - /* We come back here if a generation is full */ + if(setjmp(current_gc->gc_unwind)) + { + /* We come back here if a generation is full */ - /* We have no older generations we can try collecting, so we - resort to growing the data heap */ - if(current_gc->collecting_tenured_p()) - { - current_gc->growing_data_heap = true; + /* We have no older generations we can try collecting, so we + resort to growing the data heap */ + if(current_gc->collecting_tenured_p()) + { + current_gc->growing_data_heap = true; - /* see the comment in unmark_marked() */ - code->unmark_marked(); - } - /* we try collecting aging space twice before going on to - collect tenured */ - else if(current_gc->collecting_aging_p() - && !current_gc->collecting_aging_again) - { - current_gc->collecting_aging_again = true; - } - /* Collect the next oldest generation */ - else - { - current_gc->collecting_gen++; - } - } + /* Since we start tracing again, any previously + marked code blocks must be re-marked and re-traced */ + code->clear_mark_bits(); + } + /* we try collecting aging space twice before going on to + collect tenured */ + else if(current_gc->collecting_aging_p() + && !current_gc->collecting_aging_again) + { + current_gc->collecting_aging_again = true; + } + /* Collect the next oldest generation */ + else + { + current_gc->collecting_gen++; + } + } - if(current_gc->collecting_nursery_p()) - collect_nursery(); - else if(current_gc->collecting_aging_p()) + if(current_gc->collecting_nursery_p()) + collect_nursery(); + else if(current_gc->collecting_aging_p()) { if(current_gc->collecting_aging_again) collect_to_tenured(); From a4ea6ad339c133e0b45ac759c578ebeffbf3ce77 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 03:20:06 -0500 Subject: [PATCH 55/63] vm: record bytes/objects copied again --- vm/collector.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vm/collector.hpp b/vm/collector.hpp index 2f1c34bd8c..bb6c4042b9 100644 --- a/vm/collector.hpp +++ b/vm/collector.hpp @@ -80,6 +80,10 @@ template struct collector { memcpy(newpointer,untagged,size); untagged->h.forward_to(newpointer); + generation_statistics *stats = &myvm->gc_stats.generations[current_gc->collecting_gen]; + stats->object_count++; + stats->bytes_copied += size; + return newpointer; } From 95722adebcaa4feb37333d788f023f7b5b46040b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 03:20:50 -0500 Subject: [PATCH 56/63] vm: misc cleanups --- vm/alien.cpp | 8 ++-- vm/data_heap.cpp | 2 +- vm/heap.cpp | 4 +- vm/heap.hpp | 2 +- vm/image.cpp | 105 ++++++++++++++++++++++--------------------- vm/layouts.hpp | 2 +- vm/old_space.cpp | 23 ++++------ vm/old_space.hpp | 16 +++---- vm/vm.hpp | 22 ++++----- vm/write_barrier.hpp | 1 - 10 files changed, 86 insertions(+), 99 deletions(-) diff --git a/vm/alien.cpp b/vm/alien.cpp index 0d2a45d134..537a62de9a 100755 --- a/vm/alien.cpp +++ b/vm/alien.cpp @@ -14,7 +14,7 @@ char *factor_vm::pinned_alien_offset(cell obj) alien *ptr = untag(obj); if(ptr->expired != F) general_error(ERROR_EXPIRED,obj,F,NULL); - return pinned_alien_offset(ptr->alien) + ptr->displacement; + return pinned_alien_offset(ptr->base) + ptr->displacement; } case F_TYPE: return NULL; @@ -34,10 +34,10 @@ cell factor_vm::allot_alien(cell delegate_, cell displacement) { tagged delegate_alien = delegate.as(); displacement += delegate_alien->displacement; - new_alien->alien = delegate_alien->alien; + new_alien->base = delegate_alien->base; } else - new_alien->alien = delegate.value(); + new_alien->base = delegate.value(); new_alien->displacement = displacement; new_alien->expired = F; @@ -172,7 +172,7 @@ char *factor_vm::alien_offset(cell obj) alien *ptr = untag(obj); if(ptr->expired != F) general_error(ERROR_EXPIRED,obj,F,NULL); - return alien_offset(ptr->alien) + ptr->displacement; + return alien_offset(ptr->base) + ptr->displacement; } case F_TYPE: return NULL; diff --git a/vm/data_heap.cpp b/vm/data_heap.cpp index 9b0710ae52..52f815c139 100755 --- a/vm/data_heap.cpp +++ b/vm/data_heap.cpp @@ -95,7 +95,7 @@ void factor_vm::reset_generation(old_space *gen) clear_cards(gen); clear_decks(gen); - gen->clear_allot_markers(); + gen->clear_object_start_offsets(); } void factor_vm::set_data_heap(data_heap *data_) diff --git a/vm/heap.cpp b/vm/heap.cpp index 8c2d7d9ef5..9cd59c9139 100644 --- a/vm/heap.cpp +++ b/vm/heap.cpp @@ -172,9 +172,7 @@ void heap::mark_block(heap_block *block) block->set_marked_p(true); } -/* If in the middle of code GC, we have to grow the heap, data GC restarts from -scratch, so we have to unmark any marked blocks. */ -void heap::unmark_marked() +void heap::clear_mark_bits() { heap_block *scan = first_block(); diff --git a/vm/heap.hpp b/vm/heap.hpp index 52d3f98ba5..7f9cd30dbb 100644 --- a/vm/heap.hpp +++ b/vm/heap.hpp @@ -46,7 +46,7 @@ struct heap { heap_block *heap_allot(cell size, cell type); void heap_free(heap_block *block); void mark_block(heap_block *block); - void unmark_marked(); + void clear_mark_bits(); void heap_usage(cell *used, cell *total_free, cell *max_free); cell heap_size(); cell compute_heap_forwarding(); diff --git a/vm/image.cpp b/vm/image.cpp index 272309063b..c8a469fbbc 100755 --- a/vm/image.cpp +++ b/vm/image.cpp @@ -41,7 +41,6 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p) } data->tenured->here = data->tenured->start + h->data_size; - data_relocation_base = h->data_relocation_base; } void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p) @@ -65,7 +64,6 @@ void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p) } } - code_relocation_base = h->code_relocation_base; code->build_free_list(h->code_size); } @@ -147,7 +145,7 @@ void factor_vm::primitive_save_image_and_exit() exit(1); } -void factor_vm::data_fixup(cell *cell) +void factor_vm::data_fixup(cell *cell, cell data_relocation_base) { if(immediate_p(*cell)) return; @@ -155,28 +153,28 @@ void factor_vm::data_fixup(cell *cell) *cell += (data->tenured->start - data_relocation_base); } -template void factor_vm::code_fixup(Type **handle) +template void factor_vm::code_fixup(Type **handle, cell code_relocation_base) { Type *ptr = *handle; Type *new_ptr = (Type *)(((cell)ptr) + (code->seg->start - code_relocation_base)); *handle = new_ptr; } -void factor_vm::fixup_word(word *word) +void factor_vm::fixup_word(word *word, cell code_relocation_base) { if(word->code) - code_fixup(&word->code); + code_fixup(&word->code,code_relocation_base); if(word->profiling) - code_fixup(&word->profiling); - code_fixup(&word->xt); + code_fixup(&word->profiling,code_relocation_base); + code_fixup(&word->xt,code_relocation_base); } -void factor_vm::fixup_quotation(quotation *quot) +void factor_vm::fixup_quotation(quotation *quot, cell code_relocation_base) { if(quot->code) { - code_fixup("->xt); - code_fixup("->code); + code_fixup("->xt,code_relocation_base); + code_fixup("->code,code_relocation_base); } else quot->xt = (void *)lazy_jit_compile; @@ -184,39 +182,45 @@ void factor_vm::fixup_quotation(quotation *quot) void factor_vm::fixup_alien(alien *d) { - d->expired = T; + if(d->base == F) d->expired = T; } struct stack_frame_fixupper { factor_vm *myvm; + cell code_relocation_base; - explicit stack_frame_fixupper(factor_vm *myvm_) : myvm(myvm_) {} + explicit stack_frame_fixupper(factor_vm *myvm_, cell code_relocation_base_) : + myvm(myvm_), code_relocation_base(code_relocation_base_) {} void operator()(stack_frame *frame) { - myvm->code_fixup(&frame->xt); - myvm->code_fixup(&FRAME_RETURN_ADDRESS(frame,myvm)); + myvm->code_fixup(&frame->xt,code_relocation_base); + myvm->code_fixup(&FRAME_RETURN_ADDRESS(frame,myvm),code_relocation_base); } }; -void factor_vm::fixup_callstack_object(callstack *stack) +void factor_vm::fixup_callstack_object(callstack *stack, cell code_relocation_base) { - stack_frame_fixupper fixupper(this); + stack_frame_fixupper fixupper(this,code_relocation_base); iterate_callstack_object(stack,fixupper); } struct object_fixupper { factor_vm *myvm; + cell data_relocation_base; - explicit object_fixupper(factor_vm *myvm_) : myvm(myvm_) { } + explicit object_fixupper(factor_vm *myvm_, cell data_relocation_base_) : + myvm(myvm_), data_relocation_base(data_relocation_base_) { } void operator()(cell *scan) { - myvm->data_fixup(scan); + myvm->data_fixup(scan,data_relocation_base); } }; /* Initialize an object in a newly-loaded image */ -void factor_vm::relocate_object(object *object) +void factor_vm::relocate_object(object *object, + cell data_relocation_base, + cell code_relocation_base) { cell hi_tag = object->h.hi_tag(); @@ -226,26 +230,26 @@ void factor_vm::relocate_object(object *object) if(hi_tag == TUPLE_TYPE) { tuple *t = (tuple *)object; - data_fixup(&t->layout); + data_fixup(&t->layout,data_relocation_base); cell *scan = t->data(); cell *end = (cell *)((cell)object + untagged_object_size(object)); for(; scan < end; scan++) - data_fixup(scan); + data_fixup(scan,data_relocation_base); } else { - object_fixupper fixupper(this); + object_fixupper fixupper(this,data_relocation_base); do_slots((cell)object,fixupper); switch(hi_tag) { case WORD_TYPE: - fixup_word((word *)object); + fixup_word((word *)object,code_relocation_base); break; case QUOTATION_TYPE: - fixup_quotation((quotation *)object); + fixup_quotation((quotation *)object,code_relocation_base); break; case DLL_TYPE: ffi_dlopen((dll *)object); @@ -254,7 +258,7 @@ void factor_vm::relocate_object(object *object) fixup_alien((alien *)object); break; case CALLSTACK_TYPE: - fixup_callstack_object((callstack *)object); + fixup_callstack_object((callstack *)object,code_relocation_base); break; } } @@ -262,53 +266,52 @@ void factor_vm::relocate_object(object *object) /* Since the image might have been saved with a different base address than where it is loaded, we need to fix up pointers in the image. */ -void factor_vm::relocate_data() +void factor_vm::relocate_data(cell data_relocation_base, cell code_relocation_base) { - cell relocating; + for(cell i = 0; i < USER_ENV; i++) + data_fixup(&userenv[i],data_relocation_base); - cell i; - for(i = 0; i < USER_ENV; i++) - data_fixup(&userenv[i]); + data_fixup(&T,data_relocation_base); + data_fixup(&bignum_zero,data_relocation_base); + data_fixup(&bignum_pos_one,data_relocation_base); + data_fixup(&bignum_neg_one,data_relocation_base); - data_fixup(&T); - data_fixup(&bignum_zero); - data_fixup(&bignum_pos_one); - data_fixup(&bignum_neg_one); + cell obj = data->tenured->start; - for(relocating = data->tenured->start; - relocating < data->tenured->here; - relocating += untagged_object_size((object *)relocating)) + while(obj) { - object *obj = (object *)relocating; - data->tenured->record_allocation(obj); - relocate_object(obj); + relocate_object((object *)obj,data_relocation_base,code_relocation_base); + data->tenured->record_object_start_offset((object *)obj); + obj = data->tenured->next_object_after(this,obj); } } -void factor_vm::fixup_code_block(code_block *compiled) +void factor_vm::fixup_code_block(code_block *compiled, cell data_relocation_base) { /* relocate literal table data */ - data_fixup(&compiled->owner); - data_fixup(&compiled->literals); - data_fixup(&compiled->relocation); + data_fixup(&compiled->owner,data_relocation_base); + data_fixup(&compiled->literals,data_relocation_base); + data_fixup(&compiled->relocation,data_relocation_base); relocate_code_block(compiled); } struct code_block_fixupper { factor_vm *myvm; + cell data_relocation_base; - code_block_fixupper(factor_vm *myvm_) : myvm(myvm_) { } + code_block_fixupper(factor_vm *myvm_, cell data_relocation_base_) : + myvm(myvm_), data_relocation_base(data_relocation_base_) { } void operator()(code_block *compiled) { - myvm->fixup_code_block(compiled); + myvm->fixup_code_block(compiled,data_relocation_base); } }; -void factor_vm::relocate_code() +void factor_vm::relocate_code(cell data_relocation_base) { - code_block_fixupper fixupper(this); + code_block_fixupper fixupper(this,data_relocation_base); iterate_code_heap(fixupper); } @@ -341,8 +344,8 @@ void factor_vm::load_image(vm_parameters *p) init_objects(&h); - relocate_data(); - relocate_code(); + relocate_data(h.data_relocation_base,h.code_relocation_base); + relocate_code(h.data_relocation_base); /* Store image path name */ userenv[IMAGE_ENV] = allot_alien(F,(cell)p->image_path); diff --git a/vm/layouts.hpp b/vm/layouts.hpp index 68e2c7d87a..25db79b00a 100644 --- a/vm/layouts.hpp +++ b/vm/layouts.hpp @@ -305,7 +305,7 @@ struct quotation : public object { struct alien : public object { static const cell type_number = ALIEN_TYPE; /* tagged */ - cell alien; + cell base; /* tagged */ cell expired; /* untagged */ diff --git a/vm/old_space.cpp b/vm/old_space.cpp index 7dcd33f533..49517dc9a6 100644 --- a/vm/old_space.cpp +++ b/vm/old_space.cpp @@ -6,25 +6,20 @@ namespace factor old_space::old_space(cell size_, cell start_) : zone(size_,start_) { cell cards_size = size_ >> card_bits; - allot_markers = new card[cards_size]; - allot_markers_end = allot_markers + cards_size; + object_start_offsets = new card[cards_size]; + object_start_offsets_end = object_start_offsets + cards_size; } old_space::~old_space() { - delete[] allot_markers; -} - -card *old_space::addr_to_allot_marker(object *a) -{ - return (card *)((((cell)a - start) >> card_bits) + (cell)allot_markers); + delete[] object_start_offsets; } /* we need to remember the first object allocated in the card */ -void old_space::record_allocation(object *obj) +void old_space::record_object_start_offset(object *obj) { - card *ptr = addr_to_allot_marker(obj); - if(*ptr == invalid_allot_marker) + card *ptr = (card *)((((cell)obj - start) >> card_bits) + (cell)object_start_offsets); + if(*ptr == card_starts_inside_object) *ptr = ((cell)obj & addr_card_mask); } @@ -33,13 +28,13 @@ object *old_space::allot(cell size) if(here + size > end) return NULL; object *obj = zone::allot(size); - record_allocation(obj); + record_object_start_offset(obj); return obj; } -void old_space::clear_allot_markers() +void old_space::clear_object_start_offsets() { - memset(allot_markers,invalid_allot_marker,size >> card_bits); + memset(object_start_offsets,card_starts_inside_object,size >> card_bits); } cell old_space::next_object_after(factor_vm *myvm, cell scan) diff --git a/vm/old_space.hpp b/vm/old_space.hpp index abaad00432..1f136e8c6c 100644 --- a/vm/old_space.hpp +++ b/vm/old_space.hpp @@ -1,27 +1,23 @@ namespace factor { -struct allot_marker { - char first_object_start; - char last_object_start; -}; +static const cell card_starts_inside_object = 0xff; struct old_space : zone { - card *allot_markers; - card *allot_markers_end; + card *object_start_offsets; + card *object_start_offsets_end; old_space(cell size_, cell start_); ~old_space(); cell first_object_in_card(cell address) { - return allot_markers[(address - start) >> card_bits]; + return object_start_offsets[(address - start) >> card_bits]; } - card *addr_to_allot_marker(object *a); - void record_allocation(object *obj); + void record_object_start_offset(object *obj); object *allot(cell size); - void clear_allot_markers(); + void clear_object_start_offsets(); cell next_object_after(factor_vm *myvm, cell scan); }; diff --git a/vm/vm.hpp b/vm/vm.hpp index 2957714d42..98199a0dbc 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -74,10 +74,6 @@ struct factor_vm cell bignum_pos_one; cell bignum_neg_one; - /* Only used during image loading */ - cell code_relocation_base; - cell data_relocation_base; - /* Method dispatch statistics */ cell megamorphic_cache_hits; cell megamorphic_cache_misses; @@ -551,16 +547,16 @@ struct factor_vm bool save_image(const vm_char *filename); void primitive_save_image(); void primitive_save_image_and_exit(); - void data_fixup(cell *cell); - template void code_fixup(Type **handle); - void fixup_word(word *word); - void fixup_quotation(quotation *quot); + void data_fixup(cell *cell, cell data_relocation_base); + template void code_fixup(Type **handle, cell code_relocation_base); + void fixup_word(word *word, cell code_relocation_base); + void fixup_quotation(quotation *quot, cell code_relocation_base); void fixup_alien(alien *d); - void fixup_callstack_object(callstack *stack); - void relocate_object(object *object); - void relocate_data(); - void fixup_code_block(code_block *compiled); - void relocate_code(); + void fixup_callstack_object(callstack *stack, cell code_relocation_base); + void relocate_object(object *object, cell data_relocation_base, cell code_relocation_base); + void relocate_data(cell data_relocation_base, cell code_relocation_base); + void fixup_code_block(code_block *compiled, cell data_relocation_base); + void relocate_code(cell data_relocation_base); void load_image(vm_parameters *p); //callstack diff --git a/vm/write_barrier.hpp b/vm/write_barrier.hpp index c8694fbe2a..bcfc0531d3 100755 --- a/vm/write_barrier.hpp +++ b/vm/write_barrier.hpp @@ -24,6 +24,5 @@ typedef u8 card_deck; static const cell deck_bits = (card_bits + 10); static const cell deck_size = (1< Date: Fri, 9 Oct 2009 03:54:41 -0500 Subject: [PATCH 57/63] Replace README.txt with readme.html --- README.txt | 154 ---------------------------------------------------- readme.html | 72 ++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 154 deletions(-) delete mode 100755 README.txt create mode 100644 readme.html diff --git a/README.txt b/README.txt deleted file mode 100755 index 016d60e68c..0000000000 --- a/README.txt +++ /dev/null @@ -1,154 +0,0 @@ -The Factor programming language -------------------------------- - -This file covers installation and basic usage of the Factor -implementation. It is not an introduction to the language itself. - -* Contents - -- Compiling the Factor VM -- Libraries needed for compilation -- Bootstrapping the Factor image -- Running Factor on Unix with X11 -- Running Factor on Mac OS X - Cocoa UI -- Running Factor on Mac OS X - X11 UI -- Running Factor on Windows -- Command line usage -- The Factor FAQ -- Source organization -- Community - -* Compiling the Factor VM - -Factor supports various platforms. For an up-to-date list, see -. - -The Factor VM is written in C++ and uses GNU extensions. When compiling -with GCC 3.x, boost::unordered_map must be installed. On GCC 4.x, Factor -uses std::tr1::unordered_map which is shipped as part of GCC. - -Run 'make' ('gmake' on *BSD) with no parameters to build the Factor VM. - -* Bootstrapping the Factor image - -Once you have compiled the Factor VM, you must bootstrap the Factor -system using the image that corresponds to your CPU architecture. - -Boot images can be obtained from . - -Once you download the right image, bootstrap Factor with the -following command line: - -./factor -i=boot..image - -Bootstrap can take a while, depending on your system. When the process -completes, a 'factor.image' file will be generated. Note that this image -is both CPU and OS-specific, so in general cannot be shared between -machines. - -* Running Factor on Unix with X11 - -On Unix, Factor can either run a graphical user interface using X11, or -a terminal listener. - -For X11 support, you need recent development libraries for libc, -Pango, X11, and OpenGL. On a Debian-derived Linux distribution -(like Ubuntu), you can use the following line to grab everything: - - sudo apt-get install libc6-dev libpango1.0-dev libx11-dev libgl1-mesa-dev - -Note that if you are using a proprietary OpenGL driver, you should -probably leave out the last package in the list. - -If your DISPLAY environment variable is set, the UI will start -automatically when you run Factor: - - ./factor - -To run an interactive terminal listener: - - ./factor -run=listener - -* Running Factor on Mac OS X - Cocoa UI - -On Mac OS X, a Cocoa UI is available in addition to the terminal -listener. - -The 'factor' executable runs the terminal listener: - - ./factor - -The 'Factor.app' bundle runs the Cocoa UI. Note that this is not a -self-contained bundle, it must be run from the same directory which -contains factor.image and the library sources. - -* Running Factor on Mac OS X - X11 UI - -The X11 UI is also available on Mac OS X, however its use is not -recommended since it does not integrate with the host OS. - -When compiling Factor, pass the X11=1 parameter: - - make X11=1 - -Then bootstrap with the following switches: - - ./factor -i=boot..image -ui-backend=x11 - -Now if $DISPLAY is set, running ./factor will start the UI. - -* Running Factor on Windows XP/Vista - -The Factor runtime is compiled into two binaries: - - factor.com - a Windows console application - factor.exe - a Windows native application, without a console - -If you did not download the binary package, you can bootstrap Factor in -the command prompt using the console application: - - factor.com -i=boot..image - -Once bootstrapped, double-clicking factor.exe or factor.com starts -the Factor UI. - -To run the listener in the command prompt: - - factor.com -run=listener - -* The Factor FAQ - -The Factor FAQ is available at the following location: - - - -* Command line usage - -Factor supports a number of command line switches. To read command line -usage documentation, enter the following in the UI listener: - - "command-line" about - -* Source organization - -The Factor source tree is organized as follows: - - build-support/ - scripts used for compiling Factor - vm/ - Factor VM - core/ - Factor core library - basis/ - Factor basis library, compiler, tools - extra/ - more libraries and applications - misc/ - editor modes, icons, etc - unmaintained/ - unmaintained contributions, please help! - -* Community - -The Factor homepage is located at . - -Factor developers meet in the #concatenative channel on the -irc.freenode.net server. Drop by if you want to discuss anything related -to Factor or language design in general. - -Have fun! - -:tabSize=2:indentSize=2:noTabs=true: diff --git a/readme.html b/readme.html new file mode 100644 index 0000000000..0604f3cb47 --- /dev/null +++ b/readme.html @@ -0,0 +1,72 @@ + +Factor + + +

The Factor programming language

+ +

Getting started

+ +

If you are reading this README file, you either downloaded a binary +package, or checked out Factor sources from the GIT repository.

+ + + +

To run Factor:

+ +

    +
  • Windows: Double-click factor.exe, or run +.\factor.com in a command prompt
  • +
  • Mac OS X: Double-click Factor.appcode> or run open +Factor.app in a Terminal
  • +
  • Unix: Run ./factorcode> in a shell
  • +
+ +

Documentation

+ +

The Factor environment includes extensive reference documentation and +a short "cookbook" to help you get started. The best way to read the +documentation is in the UI; press F1 in the UI listener to open the help +browser tool. You can also browse +the documentation online.

+ +

Command line usage

+ +

Factor supports a number of command line switches. To read command line +usage documentation, enter the following in the UI listener:

+ +
"command-line" about
+ +

Source organization

+ +The Factor source tree is organized as follows: + +
  • build-support/ - scripts used for compiling Factor (not +present in binary packages)
  • +
  • vm/ - Factor VM source code (not present in binary +packages)
  • +
  • core/ - Factor core library
  • +
  • basis/ - Factor basis library, compiler, tools
  • +
  • extra/ - more libraries and applications
  • +
  • misc/ - editor modes, icons, etc
  • +
  • unmaintained/ - unmaintained contributions, please +help!
  • + +

    Community

    + +

    Factor developers meet in the #concatenative channel on irc.freenode.net. Drop by if you want to discuss +anything related to Factor or language design in general.

    + + + +

    Have fun!

    + + + From 18d4f030cd3b89b761a69378240a02280123de97 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 04:25:25 -0500 Subject: [PATCH 58/63] alien.parser: fix behavior with restarts, reported by mnestic --- basis/alien/parser/parser-tests.factor | 16 ++++++++++++++-- basis/alien/parser/parser.factor | 4 ++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/basis/alien/parser/parser-tests.factor b/basis/alien/parser/parser-tests.factor index 195cbb78a2..061deb84c5 100644 --- a/basis/alien/parser/parser-tests.factor +++ b/basis/alien/parser/parser-tests.factor @@ -1,6 +1,7 @@ ! (c)2009 Joe Groff bsd license USING: accessors alien.c-types alien.parser alien.syntax -tools.test vocabs.parser parser ; +tools.test vocabs.parser parser eval vocabs.parser debugger +continuations ; IN: alien.parser.tests TYPEDEF: char char2 @@ -28,4 +29,15 @@ SYMBOL: not-c-type [ "not-c-type" parse-c-type ] [ no-c-type? ] must-fail-with [ "not-word" parse-c-type ] [ error>> no-word-error? ] must-fail-with -] with-file-vocabs \ No newline at end of file +] with-file-vocabs + +! Reported by mnestic +TYPEDEF: int alien-parser-test-int ! reasonably unique name... + +[ "OK!" ] [ + [ + "USE: specialized-arrays SPECIALIZED-ARRAY: alien-parser-test-int" eval( -- ) + ! after restart, we end up here + "OK!" + ] [ :1 ] recover +] unit-test \ No newline at end of file diff --git a/basis/alien/parser/parser.factor b/basis/alien/parser/parser.factor index 67f1d4e5fd..e4ff5789d2 100644 --- a/basis/alien/parser/parser.factor +++ b/basis/alien/parser/parser.factor @@ -8,7 +8,7 @@ namespaces summary math vocabs.parser ; IN: alien.parser : parse-c-type-name ( name -- word ) - dup search [ nip ] [ no-word ] if* ; + dup search [ ] [ no-word ] ?if ; : parse-c-type ( string -- type ) { @@ -17,7 +17,7 @@ IN: alien.parser { [ dup search c-type-word? ] [ parse-c-type-name ] } { [ "**" ?tail ] [ drop void* ] } { [ "*" ?tail ] [ parse-c-type-name resolve-pointer-type ] } - [ parse-c-type-name no-c-type ] + [ dup search [ no-c-type ] [ no-word ] ?if ] } cond ; : scan-c-type ( -- c-type ) From b88fde04d9254c5c0f2309c04f2ab7dcc03a48f1 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 04:46:29 -0500 Subject: [PATCH 59/63] alien.syntax: add C-GLOBAL: for defining words to access global variables, and remove the gimpy one from core-text.utilities --- basis/alien/libraries/libraries-docs.factor | 8 ++-- basis/alien/syntax/syntax-docs.factor | 17 +++++--- basis/alien/syntax/syntax.factor | 9 +++++ basis/core-text/core-text.factor | 18 ++++----- basis/core-text/fonts/fonts.factor | 44 ++++++++++----------- basis/core-text/utilities/authors.txt | 1 - basis/core-text/utilities/utilities.factor | 10 ----- core/alien/alien-docs.factor | 8 ++++ extra/curses/ffi/ffi.factor | 5 +-- 9 files changed, 67 insertions(+), 53 deletions(-) delete mode 100644 basis/core-text/utilities/authors.txt delete mode 100644 basis/core-text/utilities/utilities.factor diff --git a/basis/alien/libraries/libraries-docs.factor b/basis/alien/libraries/libraries-docs.factor index 55537890b8..bface7f45a 100755 --- a/basis/alien/libraries/libraries-docs.factor +++ b/basis/alien/libraries/libraries-docs.factor @@ -45,10 +45,12 @@ HELP: load-library HELP: add-library { $values { "name" string } { "path" string } { "abi" "one of " { $snippet "\"cdecl\"" } " or " { $snippet "\"stdcall\"" } } } -{ $description "Defines a new logical library named " { $snippet "name" } " located in the file system at " { $snippet "path" } "and the specified ABI." } -{ $notes "Because the entire source file is parsed before top-level forms are executed, " { $link add-library } " cannot be used in the same file as " { $link POSTPONE: FUNCTION: } " definitions from that library. The " { $link add-library } " call will happen too late, after compilation, and the alien calls will not work." +{ $description "Defines a new logical library named " { $snippet "name" } " located in the file system at " { $snippet "path" } " and the specified ABI. The logical library name can then be used by a " { $link POSTPONE: LIBRARY: } " form to specify the logical library for subsequent " { $link POSTPONE: FUNCTION: } " definitions." } +{ $notes "Because the entire source file is parsed before top-level forms are executed, " { $link add-library } " must be placed within a " { $snippet "<< ... >>" } " parse-time evaluation block." $nl -"Instead, " { $link add-library } " calls must either be placed in different source files from those that use that library, or alternatively, " { $link "syntax-immediate" } " can be used to load the library before compilation." } +"This ensures that if the logical library is later used in the same file, for example by a " { $link POSTPONE: FUNCTION: } " definition. Otherwise, the " { $link add-library } " call will happen too late, after compilation, and the C function calls will not refer to the correct library." +$nl +"For details about parse-time evaluation, see " { $link "syntax-immediate" } "." } { $examples "Here is a typical usage of " { $link add-library } ":" { $code "<< \"freetype\" {" diff --git a/basis/alien/syntax/syntax-docs.factor b/basis/alien/syntax/syntax-docs.factor index 0021c2cdee..a8d3048b82 100644 --- a/basis/alien/syntax/syntax-docs.factor +++ b/basis/alien/syntax/syntax-docs.factor @@ -1,5 +1,6 @@ IN: alien.syntax -USING: alien alien.c-types alien.parser classes.struct help.markup help.syntax see ; +USING: alien alien.c-types alien.parser alien.libraries +classes.struct help.markup help.syntax see ; HELP: DLL" { $syntax "DLL\" path\"" } @@ -21,7 +22,8 @@ ARTICLE: "syntax-aliens" "Alien object literal syntax" HELP: LIBRARY: { $syntax "LIBRARY: name" } { $values { "name" "a logical library name" } } -{ $description "Sets the logical library for consequent " { $link POSTPONE: FUNCTION: } " definitions that follow." } ; +{ $description "Sets the logical library for consequent " { $link POSTPONE: FUNCTION: } ", " { $link POSTPONE: C-GLOBAL: } " and " { $link POSTPONE: CALLBACK: } " definitions, as well as " { $link POSTPONE: &: } " forms." } +{ $notes "Logical library names are defined with the " { $link add-library } " word." } ; HELP: FUNCTION: { $syntax "FUNCTION: return name ( parameters )" } @@ -96,21 +98,26 @@ HELP: CALLBACK: HELP: &: { $syntax "&: symbol" } -{ $values { "symbol" "A C library symbol name" } } +{ $values { "symbol" "A C global variable name" } } { $description "Pushes the address of a symbol named " { $snippet "symbol" } " from the current library, set with " { $link POSTPONE: LIBRARY: } "." } ; HELP: typedef -{ $values { "old" "a string" } { "new" "a string" } } +{ $values { "old" "a C type" } { "new" "a C type" } } { $description "Aliases the C type " { $snippet "old" } " under the name " { $snippet "new" } "." } { $notes "Using this word in the same source file which defines C bindings can cause problems, because words are compiled before top-level forms are run. Use the " { $link POSTPONE: TYPEDEF: } " word instead." } ; { POSTPONE: TYPEDEF: typedef } related-words HELP: c-struct? -{ $values { "c-type" "a C type name" } { "?" "a boolean" } } +{ $values { "c-type" "a C type" } { "?" "a boolean" } } { $description "Tests if a C type is a structure defined by " { $link POSTPONE: STRUCT: } "." } ; HELP: define-function { $values { "return" "a C return type" } { "library" "a logical library name" } { "function" "a C function name" } { "parameters" "a sequence of C parameter types" } } { $description "Defines a word named " { $snippet "function" } " in the current vocabulary (see " { $link "vocabularies" } "). The word calls " { $link alien-invoke } " with the specified parameters." } { $notes "This word is used to implement the " { $link POSTPONE: FUNCTION: } " parsing word." } ; + +HELP: C-GLOBAL: +{ $syntax "C-GLOBAL: type name" } +{ $values { "type" "a C type" } { "name" "a C global variable name" } } +{ $description "Defines a new word named " { $snippet "name" } " which accesses a global variable in the current library, set with " { $link POSTPONE: LIBRARY: } "." } ; diff --git a/basis/alien/syntax/syntax.factor b/basis/alien/syntax/syntax.factor index 303a3914cb..7adf837841 100644 --- a/basis/alien/syntax/syntax.factor +++ b/basis/alien/syntax/syntax.factor @@ -38,3 +38,12 @@ ERROR: no-such-symbol name library ; SYNTAX: &: scan "c-library" get '[ _ _ address-of ] over push-all ; + +: global-quot ( type word -- quot ) + name>> "c-library" get '[ _ _ address-of 0 ] + swap c-type-getter-boxer append ; + +: define-global ( type word -- ) + [ nip ] [ global-quot ] 2bi (( -- value )) define-declared ; + +SYNTAX: C-GLOBAL: scan-c-type CREATE-WORD define-global ; diff --git a/basis/core-text/core-text.factor b/basis/core-text/core-text.factor index 99849c1666..3459b368f7 100644 --- a/basis/core-text/core-text.factor +++ b/basis/core-text/core-text.factor @@ -6,19 +6,19 @@ math.order math.vectors math.rectangles math.functions locals init namespaces combinators fonts colors cache core-foundation core-foundation.strings core-foundation.attributed-strings core-foundation.utilities core-graphics core-graphics.types -core-text.fonts core-text.utilities ; +core-text.fonts ; IN: core-text TYPEDEF: void* CTLineRef -C-GLOBAL: kCTFontAttributeName -C-GLOBAL: kCTKernAttributeName -C-GLOBAL: kCTLigatureAttributeName -C-GLOBAL: kCTForegroundColorAttributeName -C-GLOBAL: kCTParagraphStyleAttributeName -C-GLOBAL: kCTUnderlineStyleAttributeName -C-GLOBAL: kCTVerticalFormsAttributeName -C-GLOBAL: kCTGlyphInfoAttributeName +C-GLOBAL: CFStringRef kCTFontAttributeName +C-GLOBAL: CFStringRef kCTKernAttributeName +C-GLOBAL: CFStringRef kCTLigatureAttributeName +C-GLOBAL: CFStringRef kCTForegroundColorAttributeName +C-GLOBAL: CFStringRef kCTParagraphStyleAttributeName +C-GLOBAL: CFStringRef kCTUnderlineStyleAttributeName +C-GLOBAL: CFStringRef kCTVerticalFormsAttributeName +C-GLOBAL: CFStringRef kCTGlyphInfoAttributeName FUNCTION: CTLineRef CTLineCreateWithAttributedString ( CFAttributedStringRef string ) ; diff --git a/basis/core-text/fonts/fonts.factor b/basis/core-text/fonts/fonts.factor index 6e85c94909..5c57034632 100644 --- a/basis/core-text/fonts/fonts.factor +++ b/basis/core-text/fonts/fonts.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors alien.c-types alien.syntax assocs core-foundation core-foundation.dictionaries core-foundation.strings -core-graphics.types core-text.utilities destructors init +core-graphics.types destructors init kernel math memoize fonts combinators unix.types ; IN: core-text.fonts @@ -18,28 +18,28 @@ TYPEDEF: void* CTFontDescriptorRef : kCTFontVerticalTrait ( -- n ) 11 2^ ; inline : kCTFontUIOptimizedTrait ( -- n ) 12 2^ ; inline -C-GLOBAL: kCTFontSymbolicTrait -C-GLOBAL: kCTFontWeightTrait -C-GLOBAL: kCTFontWidthTrait -C-GLOBAL: kCTFontSlantTrait +C-GLOBAL: CFStringRef kCTFontSymbolicTrait +C-GLOBAL: CFStringRef kCTFontWeightTrait +C-GLOBAL: CFStringRef kCTFontWidthTrait +C-GLOBAL: CFStringRef kCTFontSlantTrait -C-GLOBAL: kCTFontNameAttribute -C-GLOBAL: kCTFontDisplayNameAttribute -C-GLOBAL: kCTFontFamilyNameAttribute -C-GLOBAL: kCTFontStyleNameAttribute -C-GLOBAL: kCTFontTraitsAttribute -C-GLOBAL: kCTFontVariationAttribute -C-GLOBAL: kCTFontSizeAttribute -C-GLOBAL: kCTFontMatrixAttribute -C-GLOBAL: kCTFontCascadeListAttribute -C-GLOBAL: kCTFontCharacterSetAttribute -C-GLOBAL: kCTFontLanguagesAttribute -C-GLOBAL: kCTFontBaselineAdjustAttribute -C-GLOBAL: kCTFontMacintoshEncodingsAttribute -C-GLOBAL: kCTFontFeaturesAttribute -C-GLOBAL: kCTFontFeatureSettingsAttribute -C-GLOBAL: kCTFontFixedAdvanceAttribute -C-GLOBAL: kCTFontOrientationAttribute +C-GLOBAL: CFStringRef kCTFontNameAttribute +C-GLOBAL: CFStringRef kCTFontDisplayNameAttribute +C-GLOBAL: CFStringRef kCTFontFamilyNameAttribute +C-GLOBAL: CFStringRef kCTFontStyleNameAttribute +C-GLOBAL: CFStringRef kCTFontTraitsAttribute +C-GLOBAL: CFStringRef kCTFontVariationAttribute +C-GLOBAL: CFStringRef kCTFontSizeAttribute +C-GLOBAL: CFStringRef kCTFontMatrixAttribute +C-GLOBAL: CFStringRef kCTFontCascadeListAttribute +C-GLOBAL: CFStringRef kCTFontCharacterSetAttribute +C-GLOBAL: CFStringRef kCTFontLanguagesAttribute +C-GLOBAL: CFStringRef kCTFontBaselineAdjustAttribute +C-GLOBAL: CFStringRef kCTFontMacintoshEncodingsAttribute +C-GLOBAL: CFStringRef kCTFontFeaturesAttribute +C-GLOBAL: CFStringRef kCTFontFeatureSettingsAttribute +C-GLOBAL: CFStringRef kCTFontFixedAdvanceAttribute +C-GLOBAL: CFStringRef kCTFontOrientationAttribute FUNCTION: CTFontDescriptorRef CTFontDescriptorCreateWithAttributes ( CFDictionaryRef attributes diff --git a/basis/core-text/utilities/authors.txt b/basis/core-text/utilities/authors.txt deleted file mode 100644 index d4f5d6b3ae..0000000000 --- a/basis/core-text/utilities/authors.txt +++ /dev/null @@ -1 +0,0 @@ -Slava Pestov \ No newline at end of file diff --git a/basis/core-text/utilities/utilities.factor b/basis/core-text/utilities/utilities.factor deleted file mode 100644 index d3b1352750..0000000000 --- a/basis/core-text/utilities/utilities.factor +++ /dev/null @@ -1,10 +0,0 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: words parser alien alien.c-types kernel fry accessors -alien.libraries ; -IN: core-text.utilities - -SYNTAX: C-GLOBAL: - CREATE-WORD - dup name>> '[ _ f dlsym *void* ] - (( -- value )) define-declared ; diff --git a/core/alien/alien-docs.factor b/core/alien/alien-docs.factor index 42f37936e3..3f91b7102f 100644 --- a/core/alien/alien-docs.factor +++ b/core/alien/alien-docs.factor @@ -192,6 +192,13 @@ ARTICLE: "alien-callback" "Calling Factor from C" { $subsections "alien-callback-gc" } { $see-also "byte-arrays-gc" } ; +ARTICLE: "alien-globals" "Accessing C global variables" +"The " { $vocab-link "alien.syntax" } " vocabulary defines two parsing words for accessing the value of a global variable, and get the address of a global variable, respectively." +{ $subsections + POSTPONE: C-GLOBAL: + POSTPONE: &: +} ; + ARTICLE: "dll.private" "DLL handles" "DLL handles are a built-in class of objects which represent loaded native libraries. DLL handles are instances of the " { $link dll } " class, and have a literal syntax used for debugging prinouts; see " { $link "syntax-aliens" } "." $nl @@ -281,6 +288,7 @@ $nl "alien-callback" "c-data" "classes.struct" + "alien-globals" "dll.private" "embedding" } ; diff --git a/extra/curses/ffi/ffi.factor b/extra/curses/ffi/ffi.factor index 9a5802e73e..a9edc2e92b 100644 --- a/extra/curses/ffi/ffi.factor +++ b/extra/curses/ffi/ffi.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: accessors alien alien.syntax combinators kernel system -alien.libraries classes.struct ; +alien.c-types alien.libraries classes.struct unix.types ; IN: curses.ffi << "curses" { @@ -74,8 +74,7 @@ STRUCT: c-window LIBRARY: curses -: stdscr ( -- alien ) - "stdscr" "curses" library dll>> dlsym ; +C-GLOBAL: void* stdscr FUNCTION: WINDOW* initscr ( ) ; FUNCTION: int endwin ( ) ; From b952977d532e31237d6e6d98e3c0038b65ca5871 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 04:46:41 -0500 Subject: [PATCH 60/63] help.markup: long links don't show stack effect for parsing words and symbols --- basis/help/markup/markup.factor | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/basis/help/markup/markup.factor b/basis/help/markup/markup.factor index 845092fa03..ea64df3edc 100644 --- a/basis/help/markup/markup.factor +++ b/basis/help/markup/markup.factor @@ -5,7 +5,8 @@ combinators definitions definitions.icons effects fry generic hashtables help.stylesheet help.topics io io.styles kernel make math namespaces parser present prettyprint prettyprint.stylesheet quotations see sequences sets slots -sorting splitting strings vectors vocabs vocabs.loader words ; +sorting splitting strings vectors vocabs vocabs.loader words +words.symbol ; FROM: prettyprint.sections => with-pprint ; IN: help.markup @@ -181,12 +182,23 @@ GENERIC: link-long-text ( topic -- ) M: topic link-long-text [ article-title ] keep write-link ; +GENERIC: link-effect? ( word -- ? ) + +M: parsing-word link-effect? drop f ; +M: symbol link-effect? drop f ; +M: word link-effect? drop t ; + +: $effect ( effect -- ) + effect>string stack-effect-style get format ; + M: word link-long-text dup presented associate [ [ article-name link-style get format ] - [ drop bl ] - [ stack-effect effect>string stack-effect-style get format ] - tri + [ + dup link-effect? [ + bl stack-effect $effect + ] [ drop ] if + ] bi ] with-nesting ; : >topic ( obj -- topic ) dup topic? [ >link ] unless ; From ab9b4624115aa9b24baebd0ae4a48113e94a060a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 05:12:28 -0500 Subject: [PATCH 61/63] vm: build fix --- vm/image.cpp | 6 +++--- vm/vm.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vm/image.cpp b/vm/image.cpp index c8a469fbbc..cef318fc6a 100755 --- a/vm/image.cpp +++ b/vm/image.cpp @@ -145,12 +145,12 @@ void factor_vm::primitive_save_image_and_exit() exit(1); } -void factor_vm::data_fixup(cell *cell, cell data_relocation_base) +void factor_vm::data_fixup(cell *handle, cell data_relocation_base) { - if(immediate_p(*cell)) + if(immediate_p(*handle)) return; - *cell += (data->tenured->start - data_relocation_base); + *handle += (data->tenured->start - data_relocation_base); } template void factor_vm::code_fixup(Type **handle, cell code_relocation_base) diff --git a/vm/vm.hpp b/vm/vm.hpp index 98199a0dbc..c89268f9b6 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -547,7 +547,7 @@ struct factor_vm bool save_image(const vm_char *filename); void primitive_save_image(); void primitive_save_image_and_exit(); - void data_fixup(cell *cell, cell data_relocation_base); + void data_fixup(cell *handle, cell data_relocation_base); template void code_fixup(Type **handle, cell code_relocation_base); void fixup_word(word *word, cell code_relocation_base); void fixup_quotation(quotation *quot, cell code_relocation_base); From 639a64c2df0d243582c90895c719fa9dcb994f5b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 05:53:55 -0500 Subject: [PATCH 62/63] vm: fix integer overflow --- vm/heap.cpp | 3 ++- vm/layouts.hpp | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/vm/heap.cpp b/vm/heap.cpp index 9cd59c9139..1689af3ee4 100644 --- a/vm/heap.cpp +++ b/vm/heap.cpp @@ -13,8 +13,9 @@ void heap::clear_free_list() heap::heap(bool secure_gc_, cell size) : secure_gc(secure_gc_) { + if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size); seg = new segment(align_page(size)); - if(!seg) fatal_error("Out of memory in new_heap",size); + if(!seg) fatal_error("Out of memory in heap allocator",size); clear_free_list(); } diff --git a/vm/layouts.hpp b/vm/layouts.hpp index 25db79b00a..988fc99ec5 100644 --- a/vm/layouts.hpp +++ b/vm/layouts.hpp @@ -64,9 +64,9 @@ inline static cell align8(cell a) #define TYPE_COUNT 15 -/* Not a real type, but code_block's type field can be set to this */ -#define PIC_TYPE 42 -#define FREE_BLOCK_TYPE 69 +/* Not real types, but code_block's type can be set to this */ +#define PIC_TYPE 16 +#define FREE_BLOCK_TYPE 17 /* Constants used when floating-point trap exceptions are thrown */ enum @@ -213,16 +213,16 @@ struct heap_block header &= ~1; } - cell type() { return (header >> 1) & 0x7f; } + cell type() { return (header >> 1) & 0x1f; } void set_type(cell type) { - header = ((header & ~(0x7f << 1)) | (type << 1)); + header = ((header & ~(0x1f << 1)) | (type << 1)); } - cell size() { return (header >> 8); } + cell size() { return (header >> 6); } void set_size(cell size) { - header = (header & 0xff) | (size << 8); + header = (header & 0x2f) | (size << 6); } }; From 61e1854ca5e790831711b8b479e37b45a9ce8466 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 9 Oct 2009 09:44:09 -0500 Subject: [PATCH 63/63] compiler.codegen: fix failing tests --- basis/compiler/codegen/codegen-tests.factor | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/basis/compiler/codegen/codegen-tests.factor b/basis/compiler/codegen/codegen-tests.factor index 225577d0b9..43473ebcbb 100644 --- a/basis/compiler/codegen/codegen-tests.factor +++ b/basis/compiler/codegen/codegen-tests.factor @@ -1,14 +1,14 @@ USING: compiler.codegen.fixup tools.test cpu.architecture math kernel make -compiler.constants ; +compiler.constants words ; IN: compiler.codegen.tests -[ ] [ [ ] with-fixup drop ] unit-test -[ ] [ [ \ + %call ] with-fixup drop ] unit-test +[ ] [ gensym [ ] with-fixup drop ] unit-test +[ ] [ gensym [ \ + %call ] with-fixup drop ] unit-test -[ ] [ [