X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fpurify.c;h=3750895a703819e28f253716ed946caa59f931cc;hb=cce46771e6d734c275f3e2d5620004da3b5d09ee;hp=b7b6ecdd04b0f18162af5344c4991896c821ffae;hpb=9c9c68bd6e5e3c6d02e9f1bfd583b87bb9e85eea;p=sbcl.git diff --git a/src/runtime/purify.c b/src/runtime/purify.c index b7b6ecd..3750895 100644 --- a/src/runtime/purify.c +++ b/src/runtime/purify.c @@ -17,20 +17,17 @@ #include #include #include -#if (defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_LINUX)) -#include -#include -#endif #include +#include "sbcl.h" #include "runtime.h" #include "os.h" -#include "sbcl.h" #include "globals.h" #include "validate.h" #include "interrupt.h" #include "purify.h" #include "interr.h" +#include "fixnump.h" #include "gc.h" #include "gc-internal.h" #include "thread.h" @@ -39,9 +36,12 @@ #define PRINTNOISE -#if defined(LISP_FEATURE_X86) -/* again, what's so special about the x86 that this is differently - * visible there than on other platforms? -dan 20010125 +#if defined(LISP_FEATURE_GENCGC) +/* this is another artifact of the poor integration between gencgc and + * the rest of the runtime: on cheney gc there is a global + * dynamic_space_free_pointer which is valid whenever foreign function + * call is active, but in gencgc there's no such variable and we have + * to keep our own */ static lispobj *dynamic_space_free_pointer; #endif @@ -81,9 +81,6 @@ later { } *later_blocks = NULL; static int later_count = 0; -#define CEILING(x,y) (((x) + ((y) - 1)) & (~((y) - 1))) -#define NWORDS(x,y) (CEILING((x),(y)) / (y)) - /* FIXME: Shouldn't this be defined in sbcl.h? See also notes in * cheneygc.c */ @@ -105,7 +102,7 @@ forwarding_pointer_p(lispobj obj) static boolean dynamic_pointer_p(lispobj ptr) { -#ifndef LISP_FEATURE_X86 +#ifndef LISP_FEATURE_GENCGC return (ptr >= (lispobj)current_dynamic_space && ptr < (lispobj)dynamic_space_free_pointer); @@ -117,6 +114,22 @@ dynamic_pointer_p(lispobj ptr) #endif } +static inline lispobj * +newspace_alloc(int nwords, int constantp) +{ + lispobj *ret; + nwords=CEILING(nwords,2); + if(constantp) { + ret=read_only_free; + read_only_free+=nwords; + } else { + ret=static_free; + static_free+=nwords; + } + return ret; +} + + #ifdef LISP_FEATURE_X86 @@ -136,7 +149,9 @@ static unsigned pointer_filter_verbose = 0; /* FIXME: This is substantially the same code as * possibly_valid_dynamic_space_pointer in gencgc.c. The only * relevant difference seems to be that the gencgc code also checks - * for raw pointers into Code objects */ + * for raw pointers into Code objects, whereas in purify these are + * checked separately in setup_i386_stack_scav - they go onto + * valid_stack_ra_locations instead of just valid_stack_locations */ static int valid_dynamic_space_pointer(lispobj *pointer, lispobj *start_addr) @@ -184,11 +199,11 @@ valid_dynamic_space_pointer(lispobj *pointer, lispobj *start_addr) /* Is it plausible cons? */ if ((is_lisp_pointer(start_addr[0]) || ((start_addr[0] & 3) == 0) /* fixnum */ - || (widetag_of(start_addr[0]) == BASE_CHAR_WIDETAG) + || (widetag_of(start_addr[0]) == CHARACTER_WIDETAG) || (widetag_of(start_addr[0]) == UNBOUND_MARKER_WIDETAG)) && (is_lisp_pointer(start_addr[1]) || ((start_addr[1] & 3) == 0) /* fixnum */ - || (widetag_of(start_addr[1]) == BASE_CHAR_WIDETAG) + || (widetag_of(start_addr[1]) == CHARACTER_WIDETAG) || (widetag_of(start_addr[1]) == UNBOUND_MARKER_WIDETAG))) { break; } else { @@ -232,7 +247,7 @@ valid_dynamic_space_pointer(lispobj *pointer, lispobj *start_addr) } switch (widetag_of(start_addr[0])) { case UNBOUND_MARKER_WIDETAG: - case BASE_CHAR_WIDETAG: + case CHARACTER_WIDETAG: if (pointer_filter_verbose) { fprintf(stderr,"*Wo3: %x %x %x\n", (unsigned int) pointer, (unsigned int) start_addr, *start_addr); @@ -270,6 +285,9 @@ valid_dynamic_space_pointer(lispobj *pointer, lispobj *start_addr) #endif case SIMPLE_ARRAY_WIDETAG: case COMPLEX_BASE_STRING_WIDETAG: +#ifdef COMPLEX_CHARACTER_STRING_WIDETAG + case COMPLEX_CHARACTER_STRING_WIDETAG: +#endif case COMPLEX_VECTOR_NIL_WIDETAG: case COMPLEX_BIT_VECTOR_WIDETAG: case COMPLEX_VECTOR_WIDETAG: @@ -286,6 +304,9 @@ valid_dynamic_space_pointer(lispobj *pointer, lispobj *start_addr) #endif case SIMPLE_ARRAY_NIL_WIDETAG: case SIMPLE_BASE_STRING_WIDETAG: +#ifdef SIMPLE_CHARACTER_STRING_WIDETAG + case SIMPLE_CHARACTER_STRING_WIDETAG: +#endif case SIMPLE_BIT_VECTOR_WIDETAG: case SIMPLE_ARRAY_UNSIGNED_BYTE_2_WIDETAG: case SIMPLE_ARRAY_UNSIGNED_BYTE_4_WIDETAG: @@ -463,14 +484,7 @@ ptrans_boxed(lispobj thing, lispobj header, boolean constant) /* Allocate it */ old = (lispobj *)native_pointer(thing); - if (constant) { - new = read_only_free; - read_only_free += CEILING(nwords, 2); - } - else { - new = static_free; - static_free += CEILING(nwords, 2); - } + new = newspace_alloc(nwords,constant); /* Copy it. */ bcopy(old, new, nwords * sizeof(lispobj)); @@ -489,7 +503,7 @@ ptrans_boxed(lispobj thing, lispobj header, boolean constant) * class, and only then can we transport as constant. If it is pure, * we can ALWAYS transport as a constant. */ static lispobj -ptrans_instance(lispobj thing, lispobj header, boolean constant) +ptrans_instance(lispobj thing, lispobj header, boolean /* ignored */ constant) { lispobj layout = ((struct instance *)native_pointer(thing))->slots[0]; lispobj pure = ((struct instance *)native_pointer(layout))->slots[15]; @@ -513,8 +527,7 @@ ptrans_instance(lispobj thing, lispobj header, boolean constant) /* Allocate it */ old = (lispobj *)native_pointer(thing); - new = static_free; - static_free += CEILING(nwords, 2); + new = newspace_alloc(nwords, 0); /* inconstant */ /* Copy it. */ bcopy(old, new, nwords * sizeof(lispobj)); @@ -545,8 +558,7 @@ ptrans_fdefn(lispobj thing, lispobj header) /* Allocate it */ old = (lispobj *)native_pointer(thing); - new = static_free; - static_free += CEILING(nwords, 2); + new = newspace_alloc(nwords, 0); /* inconstant */ /* Copy it. */ bcopy(old, new, nwords * sizeof(lispobj)); @@ -575,10 +587,9 @@ ptrans_unboxed(lispobj thing, lispobj header) /* Allocate it */ old = (lispobj *)native_pointer(thing); - new = read_only_free; - read_only_free += CEILING(nwords, 2); + new = newspace_alloc(nwords,1); /* always constant */ - /* Copy it. */ + /* copy it. */ bcopy(old, new, nwords * sizeof(lispobj)); /* Deposit forwarding pointer. */ @@ -599,15 +610,7 @@ ptrans_vector(lispobj thing, int bits, int extra, vector = (struct vector *)native_pointer(thing); nwords = 2 + (CEILING((fixnum_value(vector->length)+extra)*bits,32)>>5); - if (boxed && !constant) { - new = static_free; - static_free += CEILING(nwords, 2); - } - else { - new = read_only_free; - read_only_free += CEILING(nwords, 2); - } - + new=newspace_alloc(nwords, (constant || !boxed)); bcopy(vector, new, nwords * sizeof(lispobj)); result = make_lispobj(new, lowtag_of(thing)); @@ -713,8 +716,7 @@ ptrans_code(lispobj thing) code = (struct code *)native_pointer(thing); nwords = HeaderValue(code->header) + fixnum_value(code->code_size); - new = (struct code *)read_only_free; - read_only_free += CEILING(nwords, 2); + new = (struct code *)newspace_alloc(nwords,1); /* constant */ bcopy(code, new, nwords * sizeof(lispobj)); @@ -740,11 +742,16 @@ ptrans_code(lispobj thing) /* Arrange to scavenge the debug info later. */ pscav_later(&new->debug_info, 1); - if (new->trace_table_offset & 0x3) + /* FIXME: why would this be a fixnum? */ + /* "why" is a hard word, but apparently for compiled functions the + trace_table_offset contains the length of the instructions, as + a fixnum. See CODE-INST-AREA-LENGTH in + src/compiler/target-disassem.lisp. -- CSR, 2004-01-08 */ + if (!(fixnump(new->trace_table_offset))) #if 0 - pscav(&new->trace_table_offset, 1, 0); + pscav(&new->trace_table_offset, 1, 0); #else - new->trace_table_offset = NIL; /* limit lifetime */ + new->trace_table_offset = NIL; /* limit lifetime */ #endif /* Scavenge the constants. */ @@ -759,7 +766,7 @@ ptrans_code(lispobj thing) gc_assert(!dynamic_pointer_p(func)); #ifdef LISP_FEATURE_X86 - /* Temporarly convert the self pointer to a real function pointer. */ + /* Temporarily convert the self pointer to a real function pointer. */ ((struct simple_fun *)native_pointer(func))->self -= FUN_RAW_ADDR_OFFSET; #endif @@ -812,19 +819,12 @@ ptrans_func(lispobj thing, lispobj header) nwords = 1 + HeaderValue(header); old = (lispobj *)native_pointer(thing); - /* Allocate the new one. */ - if (widetag_of(header) == FUNCALLABLE_INSTANCE_HEADER_WIDETAG) { - /* FINs *must* not go in read_only space. */ - new = static_free; - static_free += CEILING(nwords, 2); - } - else { - /* Closures can always go in read-only space, 'cause they - * never change. */ + /* Allocate the new one. FINs *must* not go in read_only + * space. Closures can; they never change */ - new = read_only_free; - read_only_free += CEILING(nwords, 2); - } + new = newspace_alloc + (nwords,(widetag_of(header)!=FUNCALLABLE_INSTANCE_HEADER_WIDETAG)); + /* Copy it. */ bcopy(old, new, nwords * sizeof(lispobj)); @@ -864,23 +864,13 @@ ptrans_list(lispobj thing, boolean constant) struct cons *old, *new, *orig; int length; - if (constant) - orig = (struct cons *)read_only_free; - else - orig = (struct cons *)static_free; + orig = (struct cons *) newspace_alloc(0,constant); length = 0; do { /* Allocate a new cons cell. */ old = (struct cons *)native_pointer(thing); - if (constant) { - new = (struct cons *)read_only_free; - read_only_free += WORDS_PER_CONS; - } - else { - new = (struct cons *)static_free; - static_free += WORDS_PER_CONS; - } + new = (struct cons *) newspace_alloc(WORDS_PER_CONS,constant); /* Copy the cons cell and keep a pointer to the cdr. */ new->car = old->car; @@ -928,6 +918,9 @@ ptrans_otherptr(lispobj thing, lispobj header, boolean constant) case COMPLEX_WIDETAG: case SIMPLE_ARRAY_WIDETAG: case COMPLEX_BASE_STRING_WIDETAG: +#ifdef COMPLEX_CHARACTER_STRING_WIDETAG + case COMPLEX_CHARACTER_STRING_WIDETAG: +#endif case COMPLEX_BIT_VECTOR_WIDETAG: case COMPLEX_VECTOR_NIL_WIDETAG: case COMPLEX_VECTOR_WIDETAG: @@ -947,6 +940,11 @@ ptrans_otherptr(lispobj thing, lispobj header, boolean constant) case SIMPLE_BASE_STRING_WIDETAG: return ptrans_vector(thing, 8, 1, 0, constant); +#ifdef SIMPLE_CHARACTER_STRING_WIDETAG + case SIMPLE_CHARACTER_STRING_WIDETAG: + return ptrans_vector(thing, 32, 1, 0, constant); +#endif + case SIMPLE_BIT_VECTOR_WIDETAG: return ptrans_vector(thing, 1, 0, 0, constant); @@ -1136,7 +1134,7 @@ pscav(lispobj *addr, int nwords, boolean constant) } count = 1; } - else if (thing & 3) { + else if (thing & 3) { /* FIXME: 3? not 2? */ /* It's an other immediate. Maybe the header for an unboxed */ /* object. */ switch (widetag_of(thing)) { @@ -1165,22 +1163,29 @@ pscav(lispobj *addr, int nwords, boolean constant) case SIMPLE_BASE_STRING_WIDETAG: vector = (struct vector *)addr; - count = CEILING(NWORDS(fixnum_value(vector->length)+1,4)+2,2); + count = CEILING(NWORDS(fixnum_value(vector->length)+1,8)+2,2); break; +#ifdef SIMPLE_CHARACTER_STRING_WIDETAG + case SIMPLE_CHARACTER_STRING_WIDETAG: + vector = (struct vector *)addr; + count = CEILING(NWORDS(fixnum_value(vector->length)+1,32)+2,2); + break; +#endif + case SIMPLE_BIT_VECTOR_WIDETAG: vector = (struct vector *)addr; - count = CEILING(NWORDS(fixnum_value(vector->length),32)+2,2); + count = CEILING(NWORDS(fixnum_value(vector->length),1)+2,2); break; case SIMPLE_ARRAY_UNSIGNED_BYTE_2_WIDETAG: vector = (struct vector *)addr; - count = CEILING(NWORDS(fixnum_value(vector->length),16)+2,2); + count = CEILING(NWORDS(fixnum_value(vector->length),2)+2,2); break; case SIMPLE_ARRAY_UNSIGNED_BYTE_4_WIDETAG: vector = (struct vector *)addr; - count = CEILING(NWORDS(fixnum_value(vector->length),8)+2,2); + count = CEILING(NWORDS(fixnum_value(vector->length),4)+2,2); break; case SIMPLE_ARRAY_UNSIGNED_BYTE_8_WIDETAG: @@ -1189,7 +1194,7 @@ pscav(lispobj *addr, int nwords, boolean constant) case SIMPLE_ARRAY_UNSIGNED_BYTE_7_WIDETAG: #endif vector = (struct vector *)addr; - count = CEILING(NWORDS(fixnum_value(vector->length),4)+2,2); + count = CEILING(NWORDS(fixnum_value(vector->length),8)+2,2); break; case SIMPLE_ARRAY_UNSIGNED_BYTE_16_WIDETAG: @@ -1198,7 +1203,7 @@ pscav(lispobj *addr, int nwords, boolean constant) case SIMPLE_ARRAY_UNSIGNED_BYTE_15_WIDETAG: #endif vector = (struct vector *)addr; - count = CEILING(NWORDS(fixnum_value(vector->length),2)+2,2); + count = CEILING(NWORDS(fixnum_value(vector->length),16)+2,2); break; case SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG: @@ -1211,9 +1216,24 @@ pscav(lispobj *addr, int nwords, boolean constant) case SIMPLE_ARRAY_UNSIGNED_BYTE_31_WIDETAG: #endif vector = (struct vector *)addr; - count = CEILING(fixnum_value(vector->length)+2,2); + count = CEILING(NWORDS(fixnum_value(vector->length),32)+2,2); break; +#if N_WORD_BITS == 64 + case SIMPLE_ARRAY_UNSIGNED_BYTE_64_WIDETAG: +#ifdef SIMPLE_ARRAY_SIGNED_BYTE_61_WIDETAG + case SIMPLE_ARRAY_SIGNED_BYTE_61_WIDETAG: + case SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG: +#endif +#ifdef SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG + case SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG: + case SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG: +#endif + vector = (struct vector *)addr; + count = CEILING(NWORDS(fixnum_value(vector->length),64)+2,2); + break; +#endif + case SIMPLE_ARRAY_SINGLE_FLOAT_WIDETAG: vector = (struct vector *)addr; count = CEILING(fixnum_value(vector->length)+2,2); @@ -1326,6 +1346,14 @@ purify(lispobj static_roots, lispobj read_only_roots) struct later *laters, *next; struct thread *thread; + if(all_threads->next) { + /* FIXME: there should be _some_ sensible error reporting + * convention. See following comment too */ + fprintf(stderr,"Can't purify when more than one thread exists\n"); + fflush(stderr); + return 0; + } + #ifdef PRINTNOISE printf("[doing purification:"); fflush(stdout); @@ -1359,23 +1387,9 @@ purify(lispobj static_roots, lispobj read_only_roots) #endif #if (defined(LISP_FEATURE_GENCGC) && defined(LISP_FEATURE_X86)) -#if 0 - /* This is what we should do, but can't unless the threads in - * question are suspended with ptrace. That's right, purify is not - * threadsafe - */ - for_each_thread(thread) { - void **ptr; - struct user_regs_struct regs; - if(ptrace(PTRACE_GETREGS,thread->pid,0,®s)){ - fprintf(stderr,"child pid %d, %s\n",thread->pid,strerror(errno)); - lose("PTRACE_GETREGS"); - } - setup_i386_stack_scav(regs.ebp, - ((void *)thread->control_stack_end)); - } -#endif /* 0 */ - /* stopgap until we can set things up as in preceding comment */ + /* note this expects only one thread to be active. We'd have to + * stop all the others in the same way as GC does if we wanted + * PURIFY to work when >1 thread exists */ setup_i386_stack_scav(((&static_roots)-2), ((void *)all_threads->control_stack_end)); #endif @@ -1503,7 +1517,7 @@ purify(lispobj static_roots, lispobj read_only_roots) SetSymbolValue(READ_ONLY_SPACE_FREE_POINTER, (lispobj)read_only_free,0); SetSymbolValue(STATIC_SPACE_FREE_POINTER, (lispobj)static_free,0); -#if !defined(LISP_FEATURE_X86) +#if !defined(ALLOCATION_POINTER) dynamic_space_free_pointer = current_dynamic_space; set_auto_gc_trigger(bytes_consed_between_gcs); #else