diff --git a/vm/arrays.hpp b/vm/arrays.hpp index 96d6dc137a..3abd78474e 100755 --- a/vm/arrays.hpp +++ b/vm/arrays.hpp @@ -10,4 +10,25 @@ inline cell array_nth(array *array, cell slot) return array->data()[slot]; } +inline void factor_vm::set_array_nth(array *array, cell slot, cell value) +{ +#ifdef FACTOR_DEBUG + assert(slot < array_capacity(array)); + assert(array->h.hi_tag() == ARRAY_TYPE); + check_tagged_pointer(value); +#endif + array->data()[slot] = value; + write_barrier(array); +} + +struct growable_array { + cell count; + gc_root elements; + + growable_array(factor_vm *myvm, cell capacity = 10) : count(0), elements(myvm->allot_array(capacity,F),myvm) {} + + void add(cell elt); + void trim(); +}; + } diff --git a/vm/booleans.hpp b/vm/booleans.hpp index 88235122a3..498c3f74be 100644 --- a/vm/booleans.hpp +++ b/vm/booleans.hpp @@ -4,4 +4,9 @@ namespace factor VM_C_API void box_boolean(bool value, factor_vm *vm); VM_C_API bool to_boolean(cell value, factor_vm *vm); +inline cell factor_vm::tag_boolean(cell untagged) +{ + return (untagged ? T : F); +} + } diff --git a/vm/byte_arrays.hpp b/vm/byte_arrays.hpp index 412ef35bb4..0d74793daf 100755 --- a/vm/byte_arrays.hpp +++ b/vm/byte_arrays.hpp @@ -1,4 +1,16 @@ namespace factor { +struct growable_byte_array { + cell count; + gc_root elements; + + growable_byte_array(factor_vm *myvm,cell capacity = 40) : count(0), elements(myvm->allot_byte_array(capacity),myvm) { } + + void append_bytes(void *elts, cell len); + void append_byte_array(cell elts); + + void trim(); +}; + } diff --git a/vm/callstack.hpp b/vm/callstack.hpp index 630332d7b0..1cfe9a763e 100755 --- a/vm/callstack.hpp +++ b/vm/callstack.hpp @@ -8,4 +8,49 @@ inline static cell callstack_size(cell size) VM_ASM_API void save_callstack_bottom(stack_frame *callstack_bottom, factor_vm *vm); +/* This is a little tricky. The iterator may allocate memory, so we +keep the callstack in a GC root and use relative offsets */ +template void factor_vm::iterate_callstack_object(callstack *stack_, TYPE &iterator) +{ + gc_root stack(stack_,this); + fixnum frame_offset = untag_fixnum(stack->length) - sizeof(stack_frame); + + while(frame_offset >= 0) + { + stack_frame *frame = stack->frame_at(frame_offset); + frame_offset -= frame->size; + iterator(frame,this); + } +} + +template void factor_vm::iterate_callstack(cell top, cell bottom, TYPE &iterator) +{ + stack_frame *frame = (stack_frame *)bottom - 1; + + while((cell)frame >= top) + { + iterator(frame,this); + frame = frame_successor(frame); + } +} + +/* Every object has a regular representation in the runtime, which makes GC +much simpler. Every slot of the object until binary_payload_start is a pointer +to some other object. */ +struct factor_vm; +inline void factor_vm::do_slots(cell obj, void (* iter)(cell *,factor_vm*)) +{ + cell scan = obj; + cell payload_start = binary_payload_start((object *)obj); + cell end = obj + payload_start; + + scan += sizeof(cell); + + while(scan < end) + { + iter((cell *)scan,this); + scan += sizeof(cell); + } +} + } diff --git a/vm/code_heap.hpp b/vm/code_heap.hpp index 412ef35bb4..df5f14a482 100755 --- a/vm/code_heap.hpp +++ b/vm/code_heap.hpp @@ -1,4 +1,11 @@ namespace factor { +inline void factor_vm::check_code_pointer(cell ptr) +{ +#ifdef FACTOR_DEBUG + assert(in_code_heap_p(ptr)); +#endif +} + } diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 58c2b914f2..d23caa798f 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -667,4 +667,68 @@ 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! + */ +object *factor_vm::allot_object(header header, cell size) +{ +#ifdef GC_DEBUG + if(!gc_off) + gc(); +#endif + + object *obj; + + if(nursery.size - allot_buffer_zone > size) + { + /* If there is insufficient room, collect the nursery */ + if(nursery.here + allot_buffer_zone + size > nursery.end) + garbage_collection(data->nursery(),false,0); + + cell h = nursery.here; + nursery.here = h + align8(size); + obj = (object *)h; + } + /* If the object is bigger than the nursery, allocate it in + tenured space */ + else + { + zone *tenured = &data->generations[data->tenured()]; + + /* If tenured space does not have enough room, collect */ + if(tenured->here + size > tenured->end) + { + gc(); + tenured = &data->generations[data->tenured()]; + } + + /* If it still won't fit, grow the heap */ + if(tenured->here + size > tenured->end) + { + garbage_collection(data->tenured(),true,size); + tenured = &data->generations[data->tenured()]; + } + + obj = allot_zone(tenured,size); + + /* Allows initialization code to store old->new pointers + without hitting the write barrier in the common case of + a nursery allocation */ + write_barrier(obj); + } + + obj->h = header; + return obj; +} + } diff --git a/vm/generic_arrays.hpp b/vm/generic_arrays.hpp index 0125cb7651..8e499a928f 100644 --- a/vm/generic_arrays.hpp +++ b/vm/generic_arrays.hpp @@ -19,4 +19,41 @@ template cell array_size(T *array) return array_size(array_capacity(array)); } +template TYPE *factor_vm::allot_array_internal(cell capacity) +{ + TYPE *array = allot(array_size(capacity)); + array->capacity = tag_fixnum(capacity); + return array; +} + +template bool factor_vm::reallot_array_in_place_p(TYPE *array, cell capacity) +{ + return in_zone(&nursery,array) && capacity <= array_capacity(array); +} + +template TYPE *factor_vm::reallot_array(TYPE *array_, cell capacity) +{ + gc_root array(array_,this); + + if(reallot_array_in_place_p(array.untagged(),capacity)) + { + array->capacity = tag_fixnum(capacity); + return array.untagged(); + } + else + { + cell to_copy = array_capacity(array.untagged()); + if(capacity < to_copy) + to_copy = capacity; + + TYPE *new_array = allot_array_internal(capacity); + + memcpy(new_array + 1,array.untagged() + 1,to_copy * TYPE::element_size); + memset((char *)(new_array + 1) + to_copy * TYPE::element_size, + 0,(capacity - to_copy) * TYPE::element_size); + + return new_array; + } +} + } diff --git a/vm/inlineimpls.hpp b/vm/inlineimpls.hpp deleted file mode 100644 index 74620dc4c1..0000000000 --- a/vm/inlineimpls.hpp +++ /dev/null @@ -1,298 +0,0 @@ -namespace factor -{ - -// I've had to copy inline implementations here to make dependencies work. Am hoping to move this code back into include files -// once the rest of the reentrant changes are done. -PD - -//data_gc.hpp -inline bool factor_vm::collecting_accumulation_gen_p() -{ - return ((data->have_aging_p() - && collecting_gen == data->aging() - && !collecting_aging_again) - || collecting_gen == data->tenured()); -} - -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! - */ -inline object *factor_vm::allot_object(header header, cell size) -{ -#ifdef GC_DEBUG - if(!gc_off) - gc(); -#endif - - object *obj; - - if(nursery.size - allot_buffer_zone > size) - { - /* If there is insufficient room, collect the nursery */ - if(nursery.here + allot_buffer_zone + size > nursery.end) - garbage_collection(data->nursery(),false,0); - - cell h = nursery.here; - nursery.here = h + align8(size); - obj = (object *)h; - } - /* If the object is bigger than the nursery, allocate it in - tenured space */ - else - { - zone *tenured = &data->generations[data->tenured()]; - - /* If tenured space does not have enough room, collect */ - if(tenured->here + size > tenured->end) - { - gc(); - tenured = &data->generations[data->tenured()]; - } - - /* If it still won't fit, grow the heap */ - if(tenured->here + size > tenured->end) - { - garbage_collection(data->tenured(),true,size); - tenured = &data->generations[data->tenured()]; - } - - obj = allot_zone(tenured,size); - - /* Allows initialization code to store old->new pointers - without hitting the write barrier in the common case of - a nursery allocation */ - write_barrier(obj); - } - - obj->h = header; - return obj; -} - -template TYPE *factor_vm::allot(cell size) -{ - return (TYPE *)allot_object(header(TYPE::type_number),size); -} - -inline void factor_vm::check_data_pointer(object *pointer) -{ -#ifdef FACTOR_DEBUG - if(!growing_data_heap) - { - assert((cell)pointer >= data->seg->start - && (cell)pointer < data->seg->end); - } -#endif -} - -inline void factor_vm::check_tagged_pointer(cell tagged) -{ -#ifdef FACTOR_DEBUG - if(!immediate_p(tagged)) - { - object *obj = untag(tagged); - check_data_pointer(obj); - obj->h.hi_tag(); - } -#endif -} - -//generic_arrays.hpp -template TYPE *factor_vm::allot_array_internal(cell capacity) -{ - TYPE *array = allot(array_size(capacity)); - array->capacity = tag_fixnum(capacity); - return array; -} - -template bool factor_vm::reallot_array_in_place_p(TYPE *array, cell capacity) -{ - return in_zone(&nursery,array) && capacity <= array_capacity(array); -} - -template TYPE *factor_vm::reallot_array(TYPE *array_, cell capacity) -{ - gc_root array(array_,this); - - if(reallot_array_in_place_p(array.untagged(),capacity)) - { - array->capacity = tag_fixnum(capacity); - return array.untagged(); - } - else - { - cell to_copy = array_capacity(array.untagged()); - if(capacity < to_copy) - to_copy = capacity; - - TYPE *new_array = allot_array_internal(capacity); - - memcpy(new_array + 1,array.untagged() + 1,to_copy * TYPE::element_size); - memset((char *)(new_array + 1) + to_copy * TYPE::element_size, - 0,(capacity - to_copy) * TYPE::element_size); - - return new_array; - } -} - -//arrays.hpp -inline void factor_vm::set_array_nth(array *array, cell slot, cell value) -{ -#ifdef FACTOR_DEBUG - assert(slot < array_capacity(array)); - assert(array->h.hi_tag() == ARRAY_TYPE); - check_tagged_pointer(value); -#endif - array->data()[slot] = value; - write_barrier(array); -} - -struct growable_array { - cell count; - gc_root elements; - - growable_array(factor_vm *myvm, cell capacity = 10) : count(0), elements(myvm->allot_array(capacity,F),myvm) {} - - void add(cell elt); - void trim(); -}; - -//byte_arrays.hpp -struct growable_byte_array { - cell count; - gc_root elements; - - growable_byte_array(factor_vm *myvm,cell capacity = 40) : count(0), elements(myvm->allot_byte_array(capacity),myvm) { } - - void append_bytes(void *elts, cell len); - void append_byte_array(cell elts); - - void trim(); -}; - -//math.hpp -inline cell factor_vm::allot_integer(fixnum x) -{ - if(x < fixnum_min || x > fixnum_max) - return tag(fixnum_to_bignum(x)); - else - return tag_fixnum(x); -} - -inline cell factor_vm::allot_cell(cell x) -{ - if(x > (cell)fixnum_max) - return tag(cell_to_bignum(x)); - else - return tag_fixnum(x); -} - -inline cell factor_vm::allot_float(double n) -{ - boxed_float *flo = allot(sizeof(boxed_float)); - flo->n = n; - return tag(flo); -} - -inline bignum *factor_vm::float_to_bignum(cell tagged) -{ - return double_to_bignum(untag_float(tagged)); -} - -inline double factor_vm::bignum_to_float(cell tagged) -{ - return bignum_to_double(untag(tagged)); -} - -inline double factor_vm::untag_float(cell tagged) -{ - return untag(tagged)->n; -} - -inline double factor_vm::untag_float_check(cell tagged) -{ - return untag_check(tagged)->n; -} - -inline fixnum factor_vm::float_to_fixnum(cell tagged) -{ - return (fixnum)untag_float(tagged); -} - -inline double factor_vm::fixnum_to_float(cell tagged) -{ - return (double)untag_fixnum(tagged); -} - -//callstack.hpp -/* This is a little tricky. The iterator may allocate memory, so we -keep the callstack in a GC root and use relative offsets */ -template void factor_vm::iterate_callstack_object(callstack *stack_, TYPE &iterator) -{ - gc_root stack(stack_,this); - fixnum frame_offset = untag_fixnum(stack->length) - sizeof(stack_frame); - - while(frame_offset >= 0) - { - stack_frame *frame = stack->frame_at(frame_offset); - frame_offset -= frame->size; - iterator(frame,this); - } -} - -//booleans.hpp -inline cell factor_vm::tag_boolean(cell untagged) -{ - return (untagged ? T : F); -} - -// callstack.hpp -template void factor_vm::iterate_callstack(cell top, cell bottom, TYPE &iterator) -{ - stack_frame *frame = (stack_frame *)bottom - 1; - - while((cell)frame >= top) - { - iterator(frame,this); - frame = frame_successor(frame); - } -} - -// data_heap.hpp -/* Every object has a regular representation in the runtime, which makes GC -much simpler. Every slot of the object until binary_payload_start is a pointer -to some other object. */ -struct factor_vm; -inline void factor_vm::do_slots(cell obj, void (* iter)(cell *,factor_vm*)) -{ - cell scan = obj; - cell payload_start = binary_payload_start((object *)obj); - cell end = obj + payload_start; - - scan += sizeof(cell); - - while(scan < end) - { - iter((cell *)scan,this); - scan += sizeof(cell); - } -} - -// code_heap.hpp - -inline void factor_vm::check_code_pointer(cell ptr) -{ -#ifdef FACTOR_DEBUG - assert(in_code_heap_p(ptr)); -#endif -} - -} diff --git a/vm/local_roots.hpp b/vm/local_roots.hpp index a827c08f9c..300a971f16 100644 --- a/vm/local_roots.hpp +++ b/vm/local_roots.hpp @@ -1,7 +1,6 @@ namespace factor { -//local_roots.hpp template struct gc_root : public tagged { diff --git a/vm/master.hpp b/vm/master.hpp index d970f1aaea..d761419ff2 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -52,26 +52,25 @@ #include "data_heap.hpp" #include "write_barrier.hpp" #include "data_gc.hpp" -#include "generic_arrays.hpp" #include "debug.hpp" -#include "arrays.hpp" #include "strings.hpp" -#include "booleans.hpp" -#include "byte_arrays.hpp" #include "tuples.hpp" #include "words.hpp" -#include "math.hpp" #include "float_bits.hpp" #include "io.hpp" #include "heap.hpp" -#include "code_heap.hpp" #include "image.hpp" -#include "callstack.hpp" #include "alien.hpp" #include "vm.hpp" #include "tagged.hpp" #include "local_roots.hpp" -#include "inlineimpls.hpp" +#include "callstack.hpp" +#include "generic_arrays.hpp" +#include "arrays.hpp" +#include "math.hpp" +#include "booleans.hpp" +#include "code_heap.hpp" +#include "byte_arrays.hpp" #include "jit.hpp" #include "quotations.hpp" #include "dispatch.hpp" diff --git a/vm/math.hpp b/vm/math.hpp index 891cc8d931..1f7eda26fa 100644 --- a/vm/math.hpp +++ b/vm/math.hpp @@ -5,12 +5,61 @@ static const fixnum fixnum_max = (((fixnum)1 << (WORD_SIZE - TAG_BITS - 1)) - 1) static const fixnum fixnum_min = (-((fixnum)1 << (WORD_SIZE - TAG_BITS - 1))); static const fixnum array_size_max = ((cell)1 << (WORD_SIZE - TAG_BITS - 2)); +inline cell factor_vm::allot_integer(fixnum x) +{ + if(x < fixnum_min || x > fixnum_max) + return tag(fixnum_to_bignum(x)); + else + return tag_fixnum(x); +} + +inline cell factor_vm::allot_cell(cell x) +{ + if(x > (cell)fixnum_max) + return tag(cell_to_bignum(x)); + else + return tag_fixnum(x); +} + +inline cell factor_vm::allot_float(double n) +{ + boxed_float *flo = allot(sizeof(boxed_float)); + flo->n = n; + return tag(flo); +} + +inline bignum *factor_vm::float_to_bignum(cell tagged) +{ + return double_to_bignum(untag_float(tagged)); +} + +inline double factor_vm::bignum_to_float(cell tagged) +{ + return bignum_to_double(untag(tagged)); +} + +inline double factor_vm::untag_float(cell tagged) +{ + return untag(tagged)->n; +} + +inline double factor_vm::untag_float_check(cell tagged) +{ + return untag_check(tagged)->n; +} + +inline fixnum factor_vm::float_to_fixnum(cell tagged) +{ + return (fixnum)untag_float(tagged); +} + +inline double factor_vm::fixnum_to_float(cell tagged) +{ + return (double)untag_fixnum(tagged); +} + // defined in assembler - - - - VM_C_API void box_float(float flo, factor_vm *vm); VM_C_API float to_float(cell value, factor_vm *vm); VM_C_API void box_double(double flo, factor_vm *vm); diff --git a/vm/vm.hpp b/vm/vm.hpp index a6a8c96899..0f8e76e480 100644 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -101,20 +101,20 @@ struct factor_vm void bignum_destructive_add(bignum * bignum, bignum_digit_type n); void bignum_destructive_scale_up(bignum * bignum, bignum_digit_type factor); void bignum_divide_unsigned_large_denominator(bignum * numerator, bignum * denominator, - bignum * * quotient, bignum * * remainder, int q_negative_p, int r_negative_p); + bignum * * quotient, bignum * * remainder, int q_negative_p, int r_negative_p); void bignum_divide_unsigned_normalized(bignum * u, bignum * v, bignum * q); bignum_digit_type bignum_divide_subtract(bignum_digit_type * v_start, bignum_digit_type * v_end, - bignum_digit_type guess, bignum_digit_type * u_start); + bignum_digit_type guess, bignum_digit_type * u_start); void bignum_divide_unsigned_medium_denominator(bignum * numerator,bignum_digit_type denominator, - bignum * * quotient, bignum * * remainder,int q_negative_p, int r_negative_p); + bignum * * quotient, bignum * * remainder,int q_negative_p, int r_negative_p); void bignum_destructive_normalization(bignum * source, bignum * target, int shift_left); void bignum_destructive_unnormalization(bignum * bignum, int shift_right); bignum_digit_type bignum_digit_divide(bignum_digit_type uh, bignum_digit_type ul, - bignum_digit_type v, bignum_digit_type * q) /* return value */; + bignum_digit_type v, bignum_digit_type * q) /* return value */; bignum_digit_type bignum_digit_divide_subtract(bignum_digit_type v1, bignum_digit_type v2, - bignum_digit_type guess, bignum_digit_type * u); + bignum_digit_type guess, bignum_digit_type * u); void bignum_divide_unsigned_small_denominator(bignum * numerator, bignum_digit_type denominator, - bignum * * quotient, bignum * * remainder,int q_negative_p, int r_negative_p); + bignum * * quotient, bignum * * remainder,int q_negative_p, int r_negative_p); bignum_digit_type bignum_destructive_scale_down(bignum * bignum, bignum_digit_type denominator); bignum * bignum_remainder_unsigned_small_denominator(bignum * n, bignum_digit_type d, int negative_p); bignum *bignum_digit_to_bignum(bignum_digit_type digit, int negative_p); @@ -171,7 +171,6 @@ struct factor_vm template void each_object(T &functor); cell find_all_words(); cell object_size(cell tagged); - //write barrier cell allot_markers_offset; @@ -282,14 +281,46 @@ struct factor_vm void clear_gc_stats(); void primitive_become(); void inline_gc(cell *gc_roots_base, cell gc_roots_size); - inline bool collecting_accumulation_gen_p(); inline object *allot_zone(zone *z, cell a); - inline object *allot_object(header header, cell size); - template TYPE *allot(cell size); - inline void check_data_pointer(object *pointer); - inline void check_tagged_pointer(cell tagged); + object *allot_object(header header, cell size); void primitive_clear_gc_stats(); + template TYPE *allot(cell size) + { + return (TYPE *)allot_object(header(TYPE::type_number),size); + } + + inline bool collecting_accumulation_gen_p() + { + return ((data->have_aging_p() + && collecting_gen == data->aging() + && !collecting_aging_again) + || collecting_gen == data->tenured()); + } + + inline void check_data_pointer(object *pointer) + { + #ifdef FACTOR_DEBUG + if(!growing_data_heap) + { + assert((cell)pointer >= data->seg->start + && (cell)pointer < data->seg->end); + } + #endif + } + + inline void check_tagged_pointer(cell tagged) + { + #ifdef FACTOR_DEBUG + if(!immediate_p(tagged)) + { + object *obj = untag(tagged); + check_data_pointer(obj); + obj->h.hi_tag(); + } + #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