From f53f20b5b94ede249bff55387ea8bdf93e4d01e2 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Sat, 18 Apr 2020 20:25:29 -0600 Subject: [PATCH] GC marking (non-copying) mode Change the GC so that it can mark and sweep objects in-place, instead of always copying. This change is helpful for reducing peak memory use while performing a collection on a large, old heap. Some non-copying support was already in place for locked objects, but the new implementation is faster and more general. As an alternative to locking, the storage manager now provides "immobile" allocation (currently only for bytevectors, vectors, and boxes), which allocates an object that won't move but that can be GCed if it's not referenced. A locked object is an object that has been immobiled and that is on a global list --- mostly the old, non-scalable implementation of locked objects brought back, since immobile objects cover the cases that need to scale. original commit: aecb7b736cb1d52764c292fa6364a674958dfde3 --- c/alloc.c | 48 +- c/externs.h | 9 +- c/gc.c | 866 ++++++++++++++++++++----------- c/gcwrapper.c | 224 +++++--- c/globals.h | 4 +- c/prim.c | 4 + c/prim5.c | 50 +- c/schlib.c | 8 +- c/segment.c | 14 +- c/segment.h | 1 + c/types.h | 13 +- c/vfasl.c | 2 +- csug/foreign.stex | 27 +- csug/smgmt.stex | 82 ++- makefiles/Mf-install.in | 2 +- mats/4.ms | 4 +- mats/Mf-base | 7 + mats/foreign.ms | 86 +-- mats/misc.ms | 190 ++++++- mats/patch-compile-0-t-f-f | 274 +++++----- mats/root-experr-compile-0-f-f-f | 13 + mats/thread.ms | 10 +- s/back.ss | 11 + s/bytevector.ss | 15 + s/cmacros.ss | 25 +- s/cpnanopass.ss | 8 +- s/mkgc.ss | 587 +++++++++++++++------ s/primdata.ss | 6 +- s/prims.ss | 24 +- 29 files changed, 1840 insertions(+), 774 deletions(-) diff --git a/c/alloc.c b/c/alloc.c index 4562d50663..c3ce93117e 100644 --- a/c/alloc.c +++ b/c/alloc.c @@ -147,7 +147,7 @@ ptr S_compute_bytes_allocated(xg, xs) ptr xg; ptr xs; { g = gmin; while (g <= gmax) { - n += S_G.phantom_sizes[g]; + n += S_G.bytesof[g][countof_phantom]; for (s = smin; s <= smax; s++) { /* add in bytes previously recorded */ n += S_G.bytes_of_space[s][g]; @@ -176,7 +176,7 @@ static void maybe_fire_collector() { ISPC s; uptr bytes, fudge; - bytes = S_G.phantom_sizes[0]; + bytes = S_G.bytesof[0][countof_phantom]; for (s = 0; s <= max_real_space; s += 1) { /* bytes already accounted for */ @@ -308,10 +308,19 @@ void S_dirty_set(ptr *loc, ptr x) { *loc = x; if (!Sfixnump(x)) { seginfo *si = SegInfo(addr_get_segment(loc)); - IGEN from_g = si->generation; - if (from_g != 0) { - si->dirty_bytes[((uptr)loc >> card_offset_bits) & ((1 << segment_card_offset_bits) - 1)] = 0; - mark_segment_dirty(si, from_g); + if (si->use_marks) { + /* GC must be in progress */ + if (!IMMEDIATE(x)) { + seginfo *t_si = SegInfo(ptr_get_segment(x)); + if (t_si->generation < si->generation) + S_error_abort("wrong-way pointer installed during GC"); + } + } else { + IGEN from_g = si->generation; + if (from_g != 0) { + si->dirty_bytes[((uptr)loc >> card_offset_bits) & ((1 << segment_card_offset_bits) - 1)] = 0; + mark_segment_dirty(si, from_g); + } } } } @@ -455,16 +464,25 @@ ptr Scons(car, cdr) ptr car, cdr; { return p; } -ptr Sbox(ref) ptr ref; { +ptr S_box2(ref, immobile) ptr ref; IBOOL immobile; { ptr tc = get_thread_context(); ptr p; - thread_find_room(tc, type_typed_object, size_box, p); + if (immobile) { + tc_mutex_acquire() + find_room(space_immobile_impure, 0, type_typed_object, size_box, p); + tc_mutex_release() + } else + thread_find_room(tc, type_typed_object, size_box, p); BOXTYPE(p) = type_box; INITBOXREF(p) = ref; return p; } +ptr Sbox(ref) ptr ref; { + return S_box2(ref, 0); +} + ptr S_symbol(name) ptr name; { ptr tc = get_thread_context(); ptr p; @@ -557,6 +575,10 @@ ptr S_fxvector(n) iptr n; { } ptr S_bytevector(n) iptr n; { + return S_bytevector2(n, 0); +} + +ptr S_bytevector2(n, immobile) iptr n; IBOOL immobile; { ptr tc; ptr p; iptr d; @@ -568,7 +590,12 @@ ptr S_bytevector(n) iptr n; { tc = get_thread_context(); d = size_bytevector(n); - thread_find_room(tc, type_typed_object, d, p); + if (immobile) { + tc_mutex_acquire() + find_room(space_immobile_data, 0, type_typed_object, d, p); + tc_mutex_release() + } else + thread_find_room(tc, type_typed_object, d, p); BYTEVECTOR_TYPE(p) = (n << bytevector_length_offset) | type_bytevector; return p; } @@ -921,7 +948,8 @@ void S_phantom_bytevector_adjust(ph, new_sz) ptr ph; uptr new_sz; { si = SegInfo(ptr_get_segment(ph)); g = si->generation; - S_G.phantom_sizes[g] += (new_sz - old_sz); + S_G.bytesof[g][countof_phantom] += (new_sz - old_sz); + S_adjustmembytes(new_sz - old_sz); PHANTOMLEN(ph) = new_sz; tc_mutex_release() diff --git a/c/externs.h b/c/externs.h index 87e646aafe..42761c9fde 100644 --- a/c/externs.h +++ b/c/externs.h @@ -79,6 +79,7 @@ extern ptr S_vector_in PROTO((ISPC s, IGEN g, iptr n)); extern ptr S_vector PROTO((iptr n)); extern ptr S_fxvector PROTO((iptr n)); extern ptr S_bytevector PROTO((iptr n)); +extern ptr S_bytevector2 PROTO((iptr n, IBOOL immobile)); extern ptr S_null_immutable_vector PROTO((void)); extern ptr S_null_immutable_fxvector PROTO((void)); extern ptr S_null_immutable_bytevector PROTO((void)); @@ -97,6 +98,7 @@ extern ptr S_bignum PROTO((ptr tc, iptr n, IBOOL sign)); extern ptr S_code PROTO((ptr tc, iptr type, iptr n)); extern ptr S_relocation_table PROTO((iptr n)); extern ptr S_weak_cons PROTO((ptr car, ptr cdr)); +extern ptr S_box2 PROTO((ptr ref, IBOOL immobile)); extern ptr S_phantom_bytevector PROTO((uptr sz)); extern void S_phantom_bytevector_adjust PROTO((ptr ph, uptr new_sz)); @@ -147,6 +149,9 @@ extern void S_set_maxgen PROTO((IGEN g)); extern IGEN S_maxgen PROTO((void)); extern void S_set_minfreegen PROTO((IGEN g)); extern IGEN S_minfreegen PROTO((void)); +extern void S_set_minmarkgen PROTO((IGEN g)); +extern IGEN S_minmarkgen PROTO((void)); +extern ptr S_locked_objects PROTO((void)); #ifndef WIN32 extern void S_register_child_process PROTO((INT child)); #endif /* WIN32 */ @@ -156,7 +161,8 @@ extern ptr S_object_counts PROTO((void)); extern IBOOL S_enable_object_backreferences PROTO((void)); extern void S_set_enable_object_backreferences PROTO((IBOOL eoc)); extern ptr S_object_backreferences PROTO((void)); -extern ptr S_locked_objects PROTO((void)); +extern void S_immobilize_object PROTO((ptr v)); +extern void S_mobilize_object PROTO((ptr v)); extern ptr S_unregister_guardian PROTO((ptr tconc)); extern void S_compact_heap PROTO((void)); extern void S_check_heap PROTO((IBOOL aftergc)); @@ -371,6 +377,7 @@ extern void S_free_chunks PROTO((void)); extern uptr S_curmembytes PROTO((void)); extern uptr S_maxmembytes PROTO((void)); extern void S_resetmaxmembytes PROTO((void)); +extern void S_adjustmembytes PROTO((iptr amt)); extern void S_move_to_chunk_list PROTO((chunkinfo *chunk, chunkinfo **pchunk_list)); /* stats.c */ diff --git a/c/gc.c b/c/gc.c index 87f55040e9..a953035889 100644 --- a/c/gc.c +++ b/c/gc.c @@ -20,20 +20,119 @@ #include #endif /* WIN32 */ #include "popcount.h" +#include + +/* + GC Implementation + ----------------- + + The copying, sweeping, and marking operations that depend on + object's shape are mostly implemented in "mkgc.ss". That script + generates "gc-ocd.inc" (for modes where object counting and + backpointers are disabled) and "gc-oce.inc". The rest of the + implementation here can still depend on representatoin details, + though, especially for pairs, weak pairs, and ephemerons. + + GC Copying versus Marking + ------------------------- + + Generations range from 0 to `S_G.max_nonstatic_generation` plus a + static generation. After an object moves to the static generation, + it doesn't move anymore. (In the case of code objects, relocations + may be discarded when the code object moves into a static + generation.) + + For the most part, collecting generations 0 through mgc (= max + copied generation) to tg (= target generation) means copying + objects from old segments into fresh segments at generation tg. + Note that tg is either the same as or one larger than mgc. + + But objects might be marked [and swept] instead of copied [and + swept] as triggered by two possibilities: one or more objects on + the source segment are immobile (subsumes locked) or mgc == tg and + the object is on a segment that hasn't been disovered as sparse by + a precious marking (non-copying) pass. Segments with marked objects + are promoted to generation tg. + + As a special case, locking on `space_new` does not mark all objects + on that segment, because dirty-write handling cannot deal with + `space_new`; only locked objects stay on the old segment in that + case, and they have to be marked by looking at a list of locked + objects. + + During a collection, the `old_space` flag is set on a segment if + objects aree being copied out of it or marked on it; that is, + `old_space` is set if the segment starts out in one of the + generations 0 through mgc. If a segment is being marked instead of + copied, the `use_marks` bit is also set; note that the bit will not + be set for a `space_new` segment, and locked objects in that space + will be specially marked. + + Marking an object means setting a bit in `marked_mask`, which is + allocated as needed. Any segments that ends up with a non-NULL + `marked_mask` is promoted to tg at the end of collection. If a + marked object spans multiple segments, then `masked_mask` is + created across all of the segments. It's possible for a segment to + end up with `marked_mask` even though `use_marks` was not set: an + marked object spanned into the segment, or it's `space_new` segment + with locked objects; in that case, other objects will be copied out + of the segment, because `use_marks` is how relocation decides + whether to copy or mark. + + If an object is copied, then its first word is set to + `forward_marker` and its second word is set to the new address. + Obviously, that doesn't happen if an object is marked. So, to test + whether an object has been reached: + + * the object must be in an `old_space` segment, otherwise it counts + as reached because it's in a generation older than mcg; + + * the object either starts with `forward_marker` or its mark bit is + set (and those arer mutually exclusive). + + Besides the one bit at the start of an object, extra bits for the + object content may be set as well. Those extra bits tell the + dirty-object sweeper which words in a previously marked page should + be swept and which should be skipped, so the extra bits are only + needed for impure objects in certain kinds of spaces. Only every + alternate word needs to be marked that way, so half of the mark + bits are usually irrelevant; the exception is that flonums can be + between normal object-start positions, so those mark bits can + matter, at least if we're preserving `eq?` on flonums (but the bits + are not relevant to dirty-object sweeping, since flonums don't have + pointer fields). + + It's mostly ok to sweep an object multiple times. An exception is + ephemerons, because an ephemeron is added to the pending set when + it is swept. + + Pending Ephemerons and Guardians + -------------------------------- + + Ephemerons and guardians act as a kind of "and": an object stays + reachable only if some other object (besdies the the + ephemeron/guardian itself) is reachable or not. Instead of + rechecking all guardians and ephemerons constantly, the collector + queues pending guardians and ephemerons on the ssegment where the + relevant object lives. If any object on that segment is discovered + to be reachable (i.e., copied or marked), the guardian/ephemeron is + put into a list of things to check again. + +*/ + /* locally defined functions */ -static uptr list_length PROTO((ptr ls)); -static ptr copy_list PROTO((ptr ls, IGEN tg)); -static ptr dosort PROTO((ptr ls, uptr n)); -static ptr domerge PROTO((ptr l1, ptr l2)); static ptr copy PROTO((ptr pp, seginfo *si)); +static ptr mark_object PROTO((ptr pp, seginfo *si)); static void sweep PROTO((ptr tc, ptr p)); static void sweep_in_old PROTO((ptr tc, ptr p)); static IBOOL object_directly_refers_to_self PROTO((ptr p)); static ptr copy_stack PROTO((ptr old, iptr *length, iptr clength)); -static void resweep_weak_pairs PROTO((IGEN g)); +static void resweep_weak_pairs PROTO((IGEN g, seginfo *oldweakspacesegments)); static void forward_or_bwp PROTO((ptr *pp, ptr p)); static void sweep_generation PROTO((ptr tc, IGEN g)); +static void sweep_from_stack PROTO((ptr tc)); +static void enlarge_sweep_stack PROTO(()); static uptr size_object PROTO((ptr p)); static iptr sweep_typed_object PROTO((ptr tc, ptr p)); static void sweep_symbol PROTO((ptr p)); @@ -47,9 +146,8 @@ static IGEN sweep_dirty_symbol PROTO((ptr x, IGEN tg, IGEN youngest)); static void sweep_code_object PROTO((ptr tc, ptr co)); static void record_dirty_segment PROTO((IGEN from_g, IGEN to_g, seginfo *si)); static void sweep_dirty PROTO((void)); -static IGEN sweep_dirty_intersecting PROTO((ptr lst, ptr *pp, ptr *ppend, IGEN tg, IGEN youngest)); -static IGEN sweep_dirty_object PROTO((ptr p, IGEN tg, IGEN youngest)); static void resweep_dirty_weak_pairs PROTO((void)); +static void mark_typemod_data_object PROTO((ptr p, uptr len, seginfo *si)); static void add_pending_guardian PROTO((ptr gdn, ptr tconc)); static void add_trigger_guardians_to_recheck PROTO((ptr ls)); static void add_ephemeron_to_pending PROTO((ptr p)); @@ -59,10 +157,11 @@ static void check_ephemeron PROTO((ptr pe, int add_to_trigger)); static void check_pending_ephemerons PROTO(()); static int check_dirty_ephemeron PROTO((ptr pe, int tg, int youngest)); static void clear_trigger_ephemerons PROTO(()); -static void sanitize_locked_segment PROTO((seginfo *si)); +static void init_fully_marked_mask(); #ifdef ENABLE_OBJECT_COUNTS static uptr total_size_so_far(); +static uptr list_length PROTO((ptr ls)); #endif static uptr target_generation_space_so_far(); @@ -81,8 +180,6 @@ static void check_ephemeron_measure(ptr pe); static void check_pending_measure_ephemerons(); #endif -#define OLDSPACE(x) (SPACE(x) & space_old) - /* #define DEBUG */ /* initialized and used each gc cycle. any others should be defined in globals.h */ @@ -98,11 +195,15 @@ static ptr recheck_guardians_ls; #ifdef ENABLE_OBJECT_COUNTS static int measure_all_enabled; static uptr count_root_bytes; -# define COUNTING_OR(e) 1 -#else -# define COUNTING_OR(e) e #endif +static ptr *sweep_stack_start, *sweep_stack, *sweep_stack_limit; +static octet *fully_marked_mask; + +#define push_sweep(p) { \ + if (sweep_stack == sweep_stack_limit) enlarge_sweep_stack(); \ + *(sweep_stack++) = p; } + #ifdef ENABLE_MEASURE static uptr measure_total; /* updated by `measure` */ static IGEN min_measure_generation, max_measure_generation; @@ -136,6 +237,16 @@ static ptr sweep_from; # define ADD_BACKREFERENCE_FROM(p, from_p) #endif +#if ptr_alignment == 2 +# define record_full_marked_mask 0x55 +# define record_high_marked_mask 0x40 +#elif ptr_alignment == 1 +# define record_full_marked_mask 0xFF +# define record_high_marked_mask 0x80 +#endif + +#define segment_sufficiently_compact_bytes ((bytes_per_segment * 3) / 4) + /* Values for a guardian entry's `pending` field when it's added to a seginfo's pending list: */ enum { @@ -143,21 +254,20 @@ enum { GUARDIAN_PENDING_FINAL }; -static ptr copy_list(ptr ls, IGEN tg) { - ptr ls2 = Snil; - for (; ls != Snil; ls = Scdr(ls)) - ls2 = S_cons_in(space_impure, tg, Scar(ls), ls2); - return ls2; -} - -#define CARLT(x, y) (Scar(x) < Scar(y)) -mkmergesort(dosort, domerge, ptr, Snil, CARLT, INITCDR) - +#ifdef ENABLE_OBJECT_COUNTS uptr list_length(ptr ls) { uptr i = 0; while (ls != Snil) { ls = Scdr(ls); i += 1; } return i; } +#endif + +#define marked(si, p) (si->marked_mask && (si->marked_mask[segment_bitmap_byte(p)] & segment_bitmap_bit(p))) + +static void init_fully_marked_mask() { + find_room(space_data, 0, typemod, ptr_align(segment_bitmap_bytes), fully_marked_mask); + memset(fully_marked_mask, 0xFF, segment_bitmap_bytes); +} #ifdef PRESERVE_FLONUM_EQ @@ -194,6 +304,14 @@ static int flonum_is_forwarded_p(ptr p, seginfo *si) { # define GET_FWDADDRESS(p) FWDADDRESS(p) #endif +#ifdef ENABLE_OBJECT_COUNTS +# define ELSE_MEASURE_NONOLDSPACE(p) \ + else if (measure_all_enabled) \ + push_measure(p); +#else +# define ELSE_MEASURE_NONOLDSPACE(p) /* empty */ +#endif + #define relocate(ppp) {\ ptr PP;\ PP = *ppp;\ @@ -208,7 +326,7 @@ static int flonum_is_forwarded_p(ptr p, seginfo *si) { #define relocate_dirty(ppp,tg,youngest) {\ ptr PP = *ppp; seginfo *SI;\ if (!IMMEDIATE(PP) && (SI = MaybeSegInfo(ptr_get_segment(PP))) != NULL) {\ - if (SI->space & space_old) {\ + if (SI->old_space) {\ relocate_help_help(ppp, PP, SI)\ youngest = tg;\ } else {\ @@ -222,18 +340,28 @@ static int flonum_is_forwarded_p(ptr p, seginfo *si) { #define relocate_help(ppp, pp) {\ seginfo *SI; \ - if (!IMMEDIATE(pp) && (SI = MaybeSegInfo(ptr_get_segment(pp))) != NULL && COUNTING_OR(SI->space & space_old)) \ - relocate_help_help(ppp, pp, SI)\ + if (!IMMEDIATE(pp) && (SI = MaybeSegInfo(ptr_get_segment(pp))) != NULL) { \ + if (SI->old_space) \ + relocate_help_help(ppp, pp, SI) \ + ELSE_MEASURE_NONOLDSPACE(pp) \ + } \ } -#define relocate_help_help(ppp, pp, si) { \ - if (FORWARDEDP(pp, si)) \ - *ppp = GET_FWDADDRESS(pp); \ - else\ - *ppp = copy(pp, si);\ +#define relocate_help_help(ppp, pp, si) { \ + if (FORWARDEDP(pp, si)) \ + *ppp = GET_FWDADDRESS(pp); \ + else if (!marked(si, pp)) \ + *ppp = copy(pp, si); \ } -#define locked(si, p) (si->locked_mask && (si->locked_mask[segment_bitmap_byte(p)] & segment_bitmap_bit(p))) +#define relocate_code(pp, si) { \ + if (FWDMARKER(pp) == forward_marker) \ + pp = GET_FWDADDRESS(pp); \ + else if (si->old_space) { \ + if (!marked(si, pp)) \ + pp = copy(pp, si); \ + } ELSE_MEASURE_NONOLDSPACE(pp) \ +} #ifdef ENABLE_OBJECT_COUNTS # define is_counting_root(si, p) (si->counting_mask && (si->counting_mask[segment_bitmap_byte(p)] & segment_bitmap_bit(p))) @@ -286,16 +414,38 @@ static void sweep_in_old(ptr tc, ptr p) { sweep(tc, p); } +static void sweep_dirty_object_if_space_new(ptr p, IGEN tg) { + seginfo *si = SegInfo(ptr_get_segment(p)); + if (si->space == space_new) + (void)sweep_dirty_object(p, tg, 0); +} + static ptr copy_stack(old, length, clength) ptr old; iptr *length, clength; { iptr n, m; ptr new; + seginfo *si = SegInfo(ptr_get_segment(old)); - /* Don't copy non-oldspace stacks, since we may be sweeping a locked + /* Don't copy non-oldspace stacks, since we may be sweeping a continuation that is older than target_generation. Doing so would be a waste of work anyway. */ - if (!OLDSPACE(old)) return old; + if (!si->old_space) return old; + + n = *length; + + if (si->use_marks) { + if (!marked(si, old)) { + mark_typemod_data_object(old, n, si); + +#ifdef ENABLE_OBJECT_COUNTS + S_G.countof[target_generation][countof_stack] += 1; + S_G.bytesof[target_generation][countof_stack] += n; +#endif + } + + return old; + } /* reduce headroom created for excessively large frames (typically resulting from apply with long lists) */ - if ((n = *length) != clength && n > default_stack_size && n > (m = clength + one_shot_headroom)) { + if (n != clength && n > default_stack_size && n > (m = clength + one_shot_headroom)) { *length = n = m; } @@ -304,6 +454,7 @@ static ptr copy_stack(old, length, clength) ptr old; iptr *length, clength; { S_G.countof[target_generation][countof_stack] += 1; S_G.bytesof[target_generation][countof_stack] += n; #endif /* ENABLE_OBJECT_COUNTS */ + find_room(space_data, target_generation, typemod, n, new); n = ptr_align(clength); /* warning: stack may have been left non-double-aligned by split_and_resize */ @@ -322,7 +473,7 @@ static ptr copy_stack(old, length, clength) ptr old; iptr *length, clength; { next = GUARDIANNEXT(ls); \ \ if (FILTER(si, obj)) { \ - if (!(si->space & space_old) || locked(si, obj)) { \ + if (!si->old_space || marked(si, obj)) { \ INITGUARDIANNEXT(ls) = pend_hold_ls; \ pend_hold_ls = ls; \ } else if (FORWARDEDP(obj, si)) { \ @@ -333,7 +484,7 @@ static ptr copy_stack(old, length, clength) ptr old; iptr *length, clength; { seginfo *t_si; \ tconc = GUARDIANTCONC(ls); \ t_si = SegInfo(ptr_get_segment(tconc)); \ - if (!(t_si->space & space_old) || locked(t_si, tconc)) { \ + if (!t_si->old_space || marked(t_si, tconc)) { \ INITGUARDIANNEXT(ls) = final_ls; \ final_ls = ls; \ } else if (FWDMARKER(tconc) == forward_marker) { \ @@ -356,10 +507,10 @@ typedef struct count_root_t { ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { IGEN g; ISPC s; - seginfo *oldspacesegments, *si, *nextsi; - ptr ls, younger_locked_objects; + seginfo *oldspacesegments, *oldweakspacesegments, *si, *nextsi; + ptr ls; bucket_pointer_list *buckets_to_rebuild; - uptr pre_finalization_size; + uptr pre_finalization_size, pre_phantom_bytes; #ifdef ENABLE_OBJECT_COUNTS ptr count_roots_counts = Snil; iptr count_roots_len; @@ -391,6 +542,9 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { target_generation = tg; max_copied_generation = mcg; + sweep_stack_start = sweep_stack = sweep_stack_limit = NULL; + fully_marked_mask = NULL; + /* set up generations to be copied */ for (s = 0; s <= max_real_space; s++) for (g = 0; g <= mcg; g++) { @@ -401,28 +555,48 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { S_G.bytes_of_space[s][g] = 0; } - /* reset phantom size in generations to be copied */ + /* reset phantom size in generations to be copied, even if counting is not otherwise enabled */ + pre_phantom_bytes = 0; for (g = 0; g <= mcg; g++) { - S_G.phantom_sizes[g] = 0; + pre_phantom_bytes += S_G.bytesof[g][countof_phantom]; + S_G.bytesof[g][countof_phantom] = 0; } + pre_phantom_bytes += S_G.bytesof[tg][countof_phantom]; /* set up target generation sweep_loc and orig_next_loc pointers */ for (s = 0; s <= max_real_space; s++) orig_next_loc[s] = sweep_loc[s] = S_G.next_loc[s][tg]; - /* mark segments from which objects are to be copied */ - oldspacesegments = (seginfo *)NULL; + /* mark segments from which objects are to be copied or marked */ + oldspacesegments = oldweakspacesegments = (seginfo *)NULL; for (s = 0; s <= max_real_space; s += 1) { for (g = 0; g <= mcg; g += 1) { + IBOOL maybe_mark = ((tg == S_G.min_mark_gen) && (g == tg)); for (si = S_G.occupied_segments[s][g]; si != NULL; si = nextsi) { nextsi = si->next; si->next = oldspacesegments; oldspacesegments = si; - si->space = s | space_old; /* NB: implicitly clearing space_locked */ + si->old_space = 1; + if (si->must_mark + || (maybe_mark && (!si->marked_mask + || (si->marked_count > segment_sufficiently_compact_bytes)))) { + if (s != space_new) /* only lock-based marking is allowed on space_new */ + si->use_marks = 1; + /* update generation now, so that any updated dirty references + will record the correct new generation; also used for a check in S_dirty_set */ + si->generation = tg; + } + si->marked_mask = NULL; /* clear old mark bits, if any */ + si->marked_count = 0; + si->min_dirty_byte = 0; /* prevent registering as dirty while GCing */ } S_G.occupied_segments[s][g] = NULL; } - } + if (s == space_weakpair) { + /* prefix of oldweakspacesegments is for weak pairs */ + oldweakspacesegments = oldspacesegments; + } + } #ifdef ENABLE_OBJECT_COUNTS /* clear object counts & bytes for copied generations; bump timestamp */ @@ -446,8 +620,25 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { S_G.gcbackreference[g] = Snil; } - SET_BACKREFERENCE(Sfalse) /* #f => root or locked */ + SET_BACKREFERENCE(Sfalse) /* #f => root */ + /* Set mark bit for any locked object in `space_new`. Don't sweep until + after handling counting roots. Note that the segment won't have + `use_marks` set, so non-locked objects will be copied out. */ + for (g = 0; g <= mcg; g += 1) { + for (ls = S_G.locked_objects[g]; ls != Snil; ls = Scdr(ls)) { + ptr p = Scar(ls); + seginfo *si = SegInfo(ptr_get_segment(p)); + if (si->space == space_new) { + if (!si->marked_mask) { + find_room(space_data, 0, typemod, ptr_align(segment_bitmap_bytes), si->marked_mask); + memset(si->marked_mask, 0, segment_bitmap_bytes); + } + si->marked_mask[segment_bitmap_byte(p)] |= segment_bitmap_bit(p); + } + } + } + #ifdef ENABLE_OBJECT_COUNTS /* set flag on count_roots objects so they get copied to space_count_root */ if (count_roots_ls != Sfalse) { @@ -471,8 +662,8 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { si->counting_mask[segment_bitmap_byte(p)] |= segment_bitmap_bit(p); count_roots[i].p = p; - count_roots[i].weak = (((ls_si->space & ~(space_old|space_locked)) == space_weakpair) - || ((ls_si->space & ~(space_old|space_locked)) == space_ephemeron)); + count_roots[i].weak = ((ls_si->space == space_weakpair) + || (ls_si->space == space_ephemeron)); } } } else { @@ -480,32 +671,6 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { count_roots = NULL; } #endif - - /* pre-collection handling of locked objects. */ - - /* set up locked-object masks */ - younger_locked_objects = Snil; - for (si = oldspacesegments; si != NULL; si = si->next) { - if (si->locked_objects != Snil) { - find_room(space_data, 0, typemod, ptr_align(segment_bitmap_bytes), si->locked_mask); - memset(si->locked_mask, 0, segment_bitmap_bytes); - - ls = copy_list(si->locked_objects, tg); - si->locked_objects = ls; - - while (ls != Snil) { - ptr p = Scar(ls); - uptr byte = segment_bitmap_byte(p); - uptr bit = segment_bitmap_bit(p); - if (!(si->locked_mask[byte] & bit)) { - si->locked_mask[byte] |= bit; - younger_locked_objects = S_cons_in(space_new, 0, p, younger_locked_objects); - } - ls = Scdr(ls); - } - } - si->unlocked_objects = Snil; - } #ifdef ENABLE_OBJECT_COUNTS /* sweep count_roots in order and accumulate counts */ @@ -527,11 +692,11 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { si->counting_mask[segment_bitmap_byte(p)] -= segment_bitmap_bit(p); - if (!(si->space & space_old) || FORWARDEDP(p, si) || locked(si, p) + if (!si->old_space || FORWARDEDP(p, si) || marked(si, p) || !count_roots[i].weak) { /* reached or older; sweep transitively */ relocate(&p) - if ((si->space & ~(space_old|space_locked)) != space_ephemeron) /* not ok to resweep ephemeron */ + if (si->space != space_ephemeron) /* not ok to resweep ephemeron */ sweep(tc, p); ADD_BACKREFERENCE(p) sweep_generation(tc, tg); @@ -573,12 +738,45 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { } #endif - /* sweep younger locked objects */ - for (ls = younger_locked_objects; ls != Snil; ls = Scdr(ls)) { - ptr x = Scar(ls); - sweep(tc, x); - ADD_BACKREFERENCE(x) - } + /* sweep older locked and unlocked objects that are on `space_new` segments, + because we can't find dirty writes there */ + for (g = mcg + 1; g <= static_generation; INCRGEN(g)) { + for (ls = S_G.locked_objects[g]; ls != Snil; ls = Scdr(ls)) + sweep_dirty_object_if_space_new(Scar(ls), tg); + for (ls = S_G.unlocked_objects[g]; ls != Snil; ls = Scdr(ls)) + sweep_dirty_object_if_space_new(Scar(ls), tg); + } + + /* Gather and mark all younger locked objects. + Any object on a `space_new` segment is already marked, but still + needs to be swept. */ + { + ptr locked_objects = ((tg > mcg) ? S_G.locked_objects[tg] : Snil); + for (g = 0; g <= mcg; g += 1) { + for (ls = S_G.locked_objects[g]; ls != Snil; ls = Scdr(ls)) { + ptr p = Scar(ls); + seginfo *si = SegInfo(ptr_get_segment(p)); + if (si->space == space_new) { + /* Retract the mark bit and mark properly, so anything that needs + to happen with marking will happen. */ + if (!marked(si, p)) + S_error_abort("space_new locked object should have a mark bit set"); + si->marked_mask[segment_bitmap_byte(p)] -= segment_bitmap_bit(p); + mark_object(p, si); + } + /* non-`space_new` objects will be swept via new pair */ + locked_objects = S_cons_in(space_impure, tg, p, locked_objects); +#ifdef ENABLE_OBJECT_COUNTS + S_G.countof[tg][countof_pair] += 1; + S_G.countof[tg][countof_locked] += 1; + S_G.bytesof[target_generation][countof_locked] += size_object(p); +#endif /* ENABLE_OBJECT_COUNTS */ + } + S_G.locked_objects[g] = Snil; + S_G.unlocked_objects[g] = Snil; + } + S_G.locked_objects[tg] = locked_objects; + } /* sweep non-oldspace threads, since any thread may have an active stack */ for (ls = S_threads; ls != Snil; ls = Scdr(ls)) { @@ -616,8 +814,11 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { } if (FWDMARKER(sym) != forward_marker && /* coordinate with alloc.c */ - (SYMVAL(sym) != sunbound || SYMPLIST(sym) != Snil || SYMSPLIST(sym) != Snil)) - (void)copy(sym, SegInfo(ptr_get_segment(sym))); + (SYMVAL(sym) != sunbound || SYMPLIST(sym) != Snil || SYMSPLIST(sym) != Snil)) { + seginfo *sym_si = SegInfo(ptr_get_segment(sym)); + if (!marked(sym_si, sym)) + (void)copy(sym, sym_si); + } } S_G.buckets_of_generation[g] = NULL; } @@ -672,10 +873,10 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { } /* invariants after partition_guardians: - * for entry in pend_hold_ls, obj is !OLDSPACE or locked - * for entry in final_ls, obj is OLDSPACE and !locked - * for entry in final_ls, tconc is !OLDSPACE or locked - * for entry in pend_final_ls, obj and tconc are OLDSPACE and !locked + * for entry in pend_hold_ls, obj is !OLDSPACE + * for entry in final_ls, obj is OLDSPACE + * for entry in final_ls, tconc is !OLDSPACE + * for entry in pend_final_ls, obj and tconc are OLDSPACE */ hold_ls = S_G.guardians[tg]; @@ -709,7 +910,8 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { representative can't itself be a tconc, so we won't discover any new tconcs at that point. */ ptr obj = GUARDIANOBJ(ls); - if (FORWARDEDP(obj, SegInfo(ptr_get_segment(obj)))) { + seginfo *o_si = SegInfo(ptr_get_segment(obj)); + if (FORWARDEDP(obj, o_si) || marked(o_si, obj)) { /* Object is reachable, so we might as well move this one to the hold list --- via pend_hold_ls, which leads to a copy to move to hold_ls */ @@ -717,7 +919,7 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { pend_hold_ls = ls; } else { seginfo *si; - if (!IMMEDIATE(rep) && (si = MaybeSegInfo(ptr_get_segment(rep))) != NULL && (si->space & space_old) && !locked(si, rep)) { + if (!IMMEDIATE(rep) && (si = MaybeSegInfo(ptr_get_segment(rep))) != NULL && si->old_space) { PUSH_BACKREFERENCE(rep) sweep_in_old(tc, rep); POP_BACKREFERENCE() @@ -732,11 +934,11 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { WITH_TOP_BACKREFERENCE(tconc, relocate(&rep)); old_end = Scdr(tconc); - new_end = S_cons_in(space_impure, 0, FIX(0), FIX(0)); + /* allocate new_end in tg, in case `tconc` is on a marked segment */ + new_end = S_cons_in(space_impure, tg, FIX(0), FIX(0)); #ifdef ENABLE_OBJECT_COUNTS S_G.countof[tg][countof_pair] += 1; #endif /* ENABLE_OBJECT_COUNTS */ - SETCAR(old_end,rep); SETCDR(old_end,new_end); SETCDR(tconc,new_end); @@ -755,7 +957,7 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { t_si = SegInfo(ptr_get_segment(tconc)); - if ((t_si->space & space_old) && !locked(t_si, tconc)) { + if (t_si->old_space && !marked(t_si, tconc)) { if (FWDMARKER(tconc) == forward_marker) tconc = FWDADDRESS(tconc); else { @@ -793,8 +995,9 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { ls = maybe_final_ordered_ls; maybe_final_ordered_ls = Snil; for (; ls != Snil; ls = next) { ptr obj = GUARDIANOBJ(ls); + seginfo *o_si = SegInfo(ptr_get_segment(obj)); next = GUARDIANNEXT(ls); - if (FORWARDEDP(obj, SegInfo(ptr_get_segment(obj)))) { + if (FORWARDEDP(obj, o_si) || marked(o_si, obj)) { /* Will defintely move to hold_ls, but the entry must be copied to move from pend_hold_ls to hold_ls: */ @@ -824,8 +1027,8 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { } /* move each entry in pend_final_ls into one of: - * final_ls if tconc forwarded - * pend_final_ls if tconc not forwarded + * final_ls if tconc forwarded or marked + * pend_final_ls if tconc not forwarded or marked * where the output pend_final_ls coresponds to pending in a segment */ ls = pend_final_ls; pend_final_ls = Snil; for ( ; ls != Snil; ls = next) { @@ -836,8 +1039,14 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { INITGUARDIANNEXT(ls) = final_ls; final_ls = ls; } else { + seginfo *t_si = SegInfo(ptr_get_segment(tconc)); + if (marked(t_si, tconc)) { + INITGUARDIANNEXT(ls) = final_ls; + final_ls = ls; + } else { INITGUARDIANPENDING(ls) = FIX(GUARDIAN_PENDING_FINAL); add_pending_guardian(ls, tconc); + } } } } @@ -846,22 +1055,15 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { } S_G.bytes_finalized = target_generation_space_so_far() - pre_finalization_size; + S_adjustmembytes(S_G.bytesof[tg][countof_phantom] - pre_phantom_bytes); /* handle weak pairs */ resweep_dirty_weak_pairs(); - resweep_weak_pairs(tg); + resweep_weak_pairs(tg, oldweakspacesegments); /* still-pending ephemerons all go to bwp */ clear_trigger_ephemerons(); - /* forward car fields of locked oldspace weak pairs */ - for (ls = younger_locked_objects; ls != Snil; ls = Scdr(ls)) { - ptr x = Scar(ls); - if (Spairp(x) && (SPACE(x) & ~(space_old|space_locked)) == space_weakpair) { - forward_or_bwp(&INITCAR(x), Scar(x)); - } - } - /* post-gc oblist handling. rebuild old buckets in the target generation, pruning unforwarded symbols */ { bucket_list *bl, *blnext; bucket *b, *bnext; bucket_pointer_list *bpl; bucket **pb; ptr sym; seginfo *si; @@ -872,7 +1074,7 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { bnext = (bucket *)((uptr)(b->next) - 1); sym = b->sym; si = SegInfo(ptr_get_segment(sym)); - if (locked(si, sym) || (FWDMARKER(sym) == forward_marker && ((sym = FWDADDRESS(sym)) || 1))) { + if (marked(si, sym) || (FWDMARKER(sym) == forward_marker && ((sym = FWDADDRESS(sym)) || 1))) { find_room(space_data, tg, typemod, sizeof(bucket), b); #ifdef ENABLE_OBJECT_COUNTS S_G.countof[tg][countof_oblist] += 1; @@ -908,7 +1110,7 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { count++; p = Scar(ls); si = SegInfo(ptr_get_segment(p)); - if (!(si->space & space_old) || locked(si, p)) { + if (!si->old_space || marked(si, p)) { newls = S_cons_in(space_impure, tg, p, newls); S_G.countof[tg][countof_pair] += 1; } else if (FWDMARKER(p) == forward_marker) { @@ -944,50 +1146,31 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { } #endif /* WIN32 */ - /* post-collection handling of locked objects. This must come after - any use of relocate. */ - for (ls = younger_locked_objects; ls != Snil; ls = Scdr(ls)) { - ptr x = Scar(ls); - ptr a1, a2; uptr seg; uptr n; - - /* promote the segment(s) containing x to the target generation. - reset the space_old bit to prevent the segments from being - reclaimed; sanitize the segments to support sweeping by - sweep_dirty (since the segments may contain a mix of objects, - many of which have been discarded). */ - n = size_object(x); -#ifdef ENABLE_OBJECT_COUNTS - S_G.countof[target_generation][countof_locked] += 1; - S_G.bytesof[target_generation][countof_locked] += n; -#endif /* ENABLE_OBJECT_COUNTS */ - - a1 = UNTYPE_ANY(x); - a2 = (ptr)((uptr)a1 + n - 1); - for (seg = addr_get_segment(a1); seg <= addr_get_segment(a2); seg += 1) { - seginfo *si = SegInfo(seg); - if (!(si->space & space_locked)) { - si->generation = tg; - si->space = (si->space & ~space_old) | space_locked; - sanitize_locked_segment(si); - } - si->locked_mask = NULL; /* really only need to clear the first one */ - } - } - - /* move old space segments to empty space */ + /* move copied old space segments to empty space, and promote + marked old space segments to the target generation */ for (si = oldspacesegments; si != NULL; si = nextsi) { nextsi = si->next; - s = si->space; - if (s & space_locked) { - /* note: the oldspace bit is cleared above for locked objects */ - s &= ~space_locked; - g = si->generation; - if (g == static_generation) S_G.number_of_nonstatic_segments -= 1; - si->next = S_G.occupied_segments[s][g]; - S_G.occupied_segments[s][g] = si; + si->old_space = 0; + si->use_marks = 0; + if (si->marked_mask != NULL) { + si->min_dirty_byte = 0xff; + if (si->space != space_data) { + int d; + for (d = 0; d < cards_per_segment; d += sizeof(ptr)) { + iptr *dp = (iptr *)(si->dirty_bytes + d); + /* fill sizeof(iptr) bytes at a time with 0xff */ + *dp = -1; + } + } + si->generation = tg; + if (tg == static_generation) S_G.number_of_nonstatic_segments -= 1; + s = si->space; + si->next = S_G.occupied_segments[s][tg]; + S_G.occupied_segments[s][tg] = si; + S_G.bytes_of_space[s][tg] += si->marked_count; si->trigger_ephemerons = NULL; + si->trigger_guardians = NULL; #ifdef PRESERVE_FLONUM_EQ - /* any flonums forwarded won't be reference anymore */ si->forwarded_flonums = NULL; #endif } else { @@ -1075,6 +1258,9 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { /* tell profile_release_counters to look for bwp'd counters at least through tg */ if (S_G.prcgeneration < tg) S_G.prcgeneration = tg; + if (sweep_stack_start != sweep_stack) + S_error_abort("gc: sweep stack ended non-empty"); + if (count_roots_ls != Sfalse) { #ifdef ENABLE_OBJECT_COUNTS return count_roots_counts; @@ -1099,20 +1285,47 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) { while (pp != nl);\ *slp = (ptr)pp; -static void resweep_weak_pairs(g) IGEN g; { +static void resweep_weak_pairs(g, oldweakspacesegments) IGEN g; seginfo *oldweakspacesegments; { ptr *slp, *nlp; ptr *pp, p, *nl; + seginfo *si; sweep_loc[space_weakpair] = S_G.first_loc[space_weakpair][g]; sweep_space(space_weakpair, { forward_or_bwp(pp, p); pp += 2; }) + + for (si = oldweakspacesegments; si != NULL; si = si->next) { + if (si->space != space_weakpair) + break; + if (si->marked_mask) { + uptr i; + for (i = 0; i < segment_bitmap_bytes; i++) { + int mask = si->marked_mask[i]; + if (mask != 0) { + /* Assuming 4 pairs per 8 words */ + pp = (ptr *)build_ptr(si->number, (i << (log2_ptr_bytes+3))); + if (mask & 0x1) + forward_or_bwp(pp, *pp); + pp += 2; + if (mask & 0x4) + forward_or_bwp(pp, *pp); + pp += 2; + if (mask & 0x10) + forward_or_bwp(pp, *pp); + pp += 2; + if (mask & 0x40) + forward_or_bwp(pp, *pp); + } + } + } + } } static void forward_or_bwp(pp, p) ptr *pp; ptr p; { seginfo *si; /* adapted from relocate */ - if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && si->space & space_old && !locked(si, p)) { + if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && si->old_space && !marked(si, p)) { if (FORWARDEDP(p, si)) { *pp = GET_FWDADDRESS(p); } else { @@ -1126,6 +1339,9 @@ static void sweep_generation(tc, g) ptr tc; IGEN g; { do { change = 0; + + sweep_from_stack(tc); + sweep_space(space_impure, { SET_BACKREFERENCE(TYPE((ptr)pp, type_pair)) /* only pairs put here in backreference mode */ relocate_help(pp, p) @@ -1218,6 +1434,27 @@ static void sweep_generation(tc, g) ptr tc; IGEN g; { } while (change); } +void enlarge_sweep_stack() { + uptr sz = ptr_bytes * (sweep_stack_limit - sweep_stack_start); + uptr new_sz = 2 * ((sz == 0) ? 256 : sz); + ptr new_sweep_stack; + find_room(space_data, 0, typemod, ptr_align(new_sz), new_sweep_stack); + if (sz != 0) + memcpy(new_sweep_stack, sweep_stack_start, sz); + sweep_stack_start = (ptr *)new_sweep_stack; + sweep_stack_limit = (ptr *)((uptr)new_sweep_stack + new_sz); + sweep_stack = (ptr *)((uptr)new_sweep_stack + sz); +} + +void sweep_from_stack(tc) ptr tc; { + if (sweep_stack > sweep_stack_start) { + change = 1; + + while (sweep_stack > sweep_stack_start) + sweep(tc, *(--sweep_stack)); + } +} + static iptr sweep_typed_object(tc, p) ptr tc; ptr p; { ptr tf = TYPEFIELD(p); @@ -1258,43 +1495,6 @@ static void record_dirty_segment(IGEN from_g, IGEN to_g, seginfo *si) { } } -#define SIMPLE_DIRTY_SPACE_P(s) (((s) == space_weakpair) || ((s) == space_ephemeron) || ((s) == space_symbol) || ((s) == space_port)) - -static void sanitize_locked_segment(seginfo *si) { - /* If `si` is for weak pairs, ephemeron pairs, or other things that - are guaranteed to stay on a single segment, make the segment safe - for handling by `sweep_dirty`, where memory not occupied by - objects in `si->locked_objects` is "zeroed" out in a way that it - can be traversed. This is merely convenient and efficient for - some kinds of segments, but it's required for weak and ephemeron - pairs. */ - ISPC s = si->space & ~space_locked; - - if (SIMPLE_DIRTY_SPACE_P(s)) { - ptr ls; - ptr *pp, *ppend; - - /* Sort locked objects */ - si->locked_objects = ls = dosort(si->locked_objects, list_length(si->locked_objects)); - - pp = build_ptr(si->number, 0); - ppend = (ptr *)((uptr)pp + bytes_per_segment); - - /* Zero out unused memory */ - while (pp < ppend) { - if ((ls != Snil) && (pp == UNTYPE_ANY(Scar(ls)))) { - ptr a = Scar(ls); - pp = (ptr *)((uptr)pp + size_object(Scar(ls))); - while ((ls != Snil) && (Scar(ls) == a)) - ls = Scdr(ls); - } else { - *pp = FIX(0); - pp++; - } - } - } -} - static void sweep_dirty(void) { IGEN tg, mcg, youngest, min_youngest; ptr *pp, *ppend, *nl; @@ -1302,7 +1502,6 @@ static void sweep_dirty(void) { ISPC s; IGEN from_g, to_g; seginfo *dirty_si, *nextsi; - IBOOL check_locked; PUSH_BACKREFERENCE(Snil) /* '() => from unspecified old object */ @@ -1330,15 +1529,9 @@ static void sweep_dirty(void) { /* reset min dirty byte so we can detect if byte is set while card is swept */ dirty_si->min_dirty_byte = 0xff; - check_locked = 0; - if (s & space_locked) { - s &= ~space_locked; - if (!SIMPLE_DIRTY_SPACE_P(s)) { - /* Only consider cards that intersect with - `locked_objects`, `unlocked_objects`, or a - segment-spanning object from a preceding page */ - check_locked = 1; - } + if (dirty_si->space == space_new) { + /* Must be a space that has only locked objects, which we sweeep every time */ + continue; } min_youngest = 0xff; @@ -1372,46 +1565,23 @@ static void sweep_dirty(void) { /* assume we won't find any wrong-way pointers */ youngest = 0xff; - if (check_locked) { - /* Look only at bytes that intersect with a locked or unlocked object */ - ptr backp; - seginfo *prev_si; - - youngest = sweep_dirty_intersecting(dirty_si->locked_objects, pp, ppend, tg, youngest); - youngest = sweep_dirty_intersecting(dirty_si->unlocked_objects, pp, ppend, tg, youngest); - - /* Look for previous segment that might have locked objects running into this one */ - backp = (ptr)((uptr)build_ptr(seg, 0) - ptr_bytes); - while (1) { - ISPC s2; - prev_si = MaybeSegInfo(ptr_get_segment(backp)); - if (!prev_si) break; - s2 = prev_si->space; - if (!(s2 & space_locked)) break; - s2 &= ~space_locked; - if (SIMPLE_DIRTY_SPACE_P(s2)) break; - if ((prev_si->locked_objects != Snil) || (prev_si->unlocked_objects != Snil)) { - youngest = sweep_dirty_intersecting(prev_si->locked_objects, pp, ppend, tg, youngest); - youngest = sweep_dirty_intersecting(prev_si->unlocked_objects, pp, ppend, tg, youngest); - break; - } else { - backp = (ptr)(((uptr)backp) - bytes_per_segment); - } - } - } else if ((s == space_impure) - || (s == space_impure_typed_object) || (s == space_count_impure) - || (s == space_closure)) { + if ((s == space_impure) || (s == space_immobile_impure) + || (s == space_impure_typed_object) || (s == space_count_impure) + || (s == space_closure)) { while (pp < ppend && *pp != forward_marker) { /* handle two pointers at a time */ - relocate_dirty(pp,tg,youngest) - pp += 1; - relocate_dirty(pp,tg,youngest) - pp += 1; + if (!dirty_si->marked_mask || marked(dirty_si, pp)) { + relocate_dirty(pp,tg,youngest) + pp += 1; + relocate_dirty(pp,tg,youngest) + pp += 1; + } else + pp += 2; } } else if (s == space_symbol) { /* old symbols cannot overlap segment boundaries since any object that spans multiple - generations begins at the start of a segment, + segments begins at the start of a segment, and symbols are much smaller (we assume) than the segment size. */ pp = (ptr *)build_ptr(seg,0) + @@ -1422,14 +1592,15 @@ static void sweep_dirty(void) { while (pp < ppend && *pp != forward_marker) { /* might overshoot card by part of a symbol. no harm. */ ptr p = TYPE((ptr)pp, type_symbol); - youngest = sweep_dirty_symbol(p, tg, youngest); + if (!dirty_si->marked_mask || marked(dirty_si, p)) + youngest = sweep_dirty_symbol(p, tg, youngest); pp += size_symbol / sizeof(ptr); } } else if (s == space_port) { /* old ports cannot overlap segment boundaries since any object that spans multiple - generations begins at the start of a segment, + segments begins at the start of a segment, and ports are much smaller (we assume) than the segment size. */ pp = (ptr *)build_ptr(seg,0) + @@ -1440,67 +1611,159 @@ static void sweep_dirty(void) { while (pp < ppend && *pp != forward_marker) { /* might overshoot card by part of a port. no harm. */ ptr p = TYPE((ptr)pp, type_typed_object); - youngest = sweep_dirty_port(p, tg, youngest); + if (!dirty_si->marked_mask || marked(dirty_si, p)) + youngest = sweep_dirty_port(p, tg, youngest); pp += size_port / sizeof(ptr); } } else if (s == space_impure_record) { /* abandon hope all ye who enter here */ - uptr j; ptr p, pnext; seginfo *si; + ptr p; + if (dirty_si->marked_mask) { + /* To get to the start of a record, move backward as long as bytes + are marked and segment space+generation+marked is the same. */ + uptr byte = segment_bitmap_byte(pp); + uptr bit = segment_bitmap_bit(pp); + uptr at_seg = seg; + seginfo *si = dirty_si; - /* synchronize on first record that overlaps the dirty - area, then relocate any mutable pointers in that - record and those that follow within the dirty area. */ + while (si->marked_mask[byte] & (bit >> ptr_alignment)) + bit >>= ptr_alignment; + if (bit == 1) { + /* try previous byte(s) */ + while (1) { + if (byte == 0) { + seginfo *prev_si = MaybeSegInfo(at_seg-1); + if (prev_si + && (prev_si->space == si->space) + && (prev_si->generation == si->generation) + && prev_si->marked_mask + /* object can only continue from the previous segment + if that segment is fully marked (including last words) */ + && (prev_si->marked_mask[segment_bitmap_bytes-1] == record_full_marked_mask)) { + /* maybe the object continues from the previous segment, although + we don't really know... */ + at_seg -= 1; + si = prev_si; + byte = segment_bitmap_bytes-1; + } else { + /* object does not continue from the previous segment */ + break; + } + } else { + if (si->marked_mask[byte-1] == record_full_marked_mask) { + /* next byte is full, so keep looking */ + byte--; + } else if (si->marked_mask[byte-1] & record_high_marked_mask) { + /* next byte continues, but is not full, so we can start + there */ + if (at_seg != seg) { + /* in fact, we can start at the beginning of the + next segment, because that segment's + first object cannot start on this segment */ + at_seg++; + byte = 0; + si = SegInfo(at_seg); + } else { + byte--; + /* find bit contiguous with highest bit */ + while (si->marked_mask[byte] & (bit >> ptr_alignment)) + bit >>= ptr_alignment; + } + break; + } else { + /* next byte is empty, so don't go there */ + break; + } + } + } + } - /* find first segment of group of like segments */ - j = seg - 1; - while ((si = MaybeSegInfo(j)) != NULL && - si->space == s && - si->generation == from_g) - j -= 1; - j += 1; + /* `bit` and `byte` refer to a non-0 mark bit that must be + the start of an object */ + p = build_ptr(at_seg, (byte << (log2_ptr_bytes+3))); + while (bit > ptr_alignment) { + p = (ptr)((uptr)p + byte_alignment); + bit >>= ptr_alignment; + } + p = TYPE(p, type_typed_object); - /* now find first record in segment seg */ - /* we count on following fact: if an object spans two - or more segments, then he starts at the beginning - of a segment */ - for (;;) { - p = TYPE(build_ptr(j,0),type_typed_object); - pnext = (ptr)((iptr)p + - size_record_inst(UNFIX(RECORDDESCSIZE( - RECORDINSTTYPE(p))))); - if (ptr_get_segment(pnext) >= seg) break; - j = ptr_get_segment(pnext) + 1; - } + /* now sweep, but watch out for unmarked holes in the dirty region */ + while ((ptr *)UNTYPE(p, type_typed_object) < ppend) { + seginfo *si = SegInfo(ptr_get_segment(p)); + if (!marked(si, p)) { + /* skip unmarked words */ + p = (ptr)((uptr)p + byte_alignment); + } else { + /* quit on end of segment */ + if (FWDMARKER(p) == forward_marker) break; - /* now find first within dirty area */ - while ((ptr *)UNTYPE(pnext, type_typed_object) <= pp) { - p = pnext; - pnext = (ptr)((iptr)p + - size_record_inst(UNFIX(RECORDDESCSIZE( - RECORDINSTTYPE(p))))); - } + youngest = sweep_dirty_record(p, tg, youngest); + p = (ptr)((iptr)p + + size_record_inst(UNFIX(RECORDDESCSIZE( + RECORDINSTTYPE(p))))); + } + } + } else { + uptr j; ptr pnext; seginfo *si; - /* now sweep */ - while ((ptr *)UNTYPE(p, type_typed_object) < ppend) { - /* quit on end of segment */ + /* synchronize on first record that overlaps the dirty + area, then relocate any mutable pointers in that + record and those that follow within the dirty area. */ + + /* find first segment of group of like segments */ + j = seg - 1; + while ((si = MaybeSegInfo(j)) != NULL && + si->space == s && + si->generation == from_g && + !si->marked_mask) + j -= 1; + j += 1; + + /* now find first record in segment seg */ + /* we count on following fact: if an object spans two + or more segments, then it starts at the beginning + of a segment */ + for (;;) { + p = TYPE(build_ptr(j,0),type_typed_object); + pnext = (ptr)((iptr)p + + size_record_inst(UNFIX(RECORDDESCSIZE(RECORDINSTTYPE(p))))); + if (ptr_get_segment(pnext) >= seg) break; + j = ptr_get_segment(pnext) + 1; + } + + /* now find first within dirty area */ + while ((ptr *)UNTYPE(pnext, type_typed_object) <= pp) { + p = pnext; + pnext = (ptr)((iptr)p + + size_record_inst(UNFIX(RECORDDESCSIZE(RECORDINSTTYPE(p))))); + } + + /* now sweep */ + while ((ptr *)UNTYPE(p, type_typed_object) < ppend) { + /* quit on end of segment */ if (FWDMARKER(p) == forward_marker) break; - youngest = sweep_dirty_record(p, tg, youngest); - p = (ptr)((iptr)p + - size_record_inst(UNFIX(RECORDDESCSIZE( - RECORDINSTTYPE(p))))); + youngest = sweep_dirty_record(p, tg, youngest); + p = (ptr)((iptr)p + + size_record_inst(UNFIX(RECORDDESCSIZE( + RECORDINSTTYPE(p))))); + } } } else if (s == space_weakpair) { while (pp < ppend && *pp != forward_marker) { /* skip car field and handle cdr field */ - pp += 1; - relocate_dirty(pp, tg, youngest) - pp += 1; + if (!dirty_si->marked_mask || marked(dirty_si, pp)) { + pp += 1; + relocate_dirty(pp, tg, youngest) + pp += 1; + } else + pp += 2; } } else if (s == space_ephemeron) { while (pp < ppend && *pp != forward_marker) { ptr p = TYPE((ptr)pp, type_pair); - youngest = check_dirty_ephemeron(p, tg, youngest); + if (!dirty_si->marked_mask || marked(dirty_si, p)) + youngest = check_dirty_ephemeron(p, tg, youngest); pp += size_ephemeron / sizeof(ptr); } } else { @@ -1530,25 +1793,6 @@ static void sweep_dirty(void) { POP_BACKREFERENCE() } -IGEN sweep_dirty_intersecting(ptr lst, ptr *pp, ptr *ppend, IGEN tg, IGEN youngest) -{ - ptr p, *pu, *puend; - - for (; lst != Snil; lst = Scdr(lst)) { - p = (ptr *)Scar(lst); - - pu = (ptr*)UNTYPE_ANY(p); - puend = (ptr*)((uptr)pu + size_object(p)); - - if (((pu >= pp) && (pu < ppend)) - || ((puend >= pp) && (puend < ppend)) - || ((pu <= pp) && (puend >= ppend))) - youngest = sweep_dirty_object(p, tg, youngest); - } - - return youngest; -} - static void resweep_dirty_weak_pairs() { weakseginfo *ls; ptr *pp, *ppend, *nl, p; @@ -1585,8 +1829,8 @@ static void resweep_dirty_weak_pairs() { /* handle car field */ if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL) { - if (si->space & space_old) { - if (locked(si, p)) { + if (si->old_space) { + if (marked(si, p)) { youngest = tg; } else if (FORWARDEDP(p, si)) { *pp = FWDADDRESS(p); @@ -1677,8 +1921,12 @@ static void check_ephemeron(ptr pe, int add_to_trigger) { PUSH_BACKREFERENCE(pe); p = Scar(pe); - if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && si->space & space_old && !locked(si, p)) { - if (FORWARDEDP(p, si)) { + if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && si->old_space) { + if (marked(si, p)) { + relocate(&INITCDR(pe)) + if (!add_to_trigger) + EPHEMERONTRIGGERNEXT(pe) = Strue; /* in trigger list, #t means "done" */ + } else if (FORWARDEDP(p, si)) { INITCAR(pe) = FWDADDRESS(p); relocate(&INITCDR(pe)) if (!add_to_trigger) @@ -1731,8 +1979,11 @@ static int check_dirty_ephemeron(ptr pe, int tg, int youngest) { p = Scar(pe); if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL) { - if (si->space & space_old && !locked(si, p)) { - if (FORWARDEDP(p, si)) { + if (si->old_space) { + if (marked(si, p)) { + relocate(&INITCDR(pe)) + youngest = tg; + } else if (FORWARDEDP(p, si)) { INITCAR(pe) = GET_FWDADDRESS(p); relocate(&INITCDR(pe)) youngest = tg; @@ -1796,7 +2047,6 @@ static uptr total_size_so_far() { if (bytes == 0) bytes = S_G.countof[g][i] * S_G.countof_size[i]; total += bytes; } - total += S_G.phantom_sizes[g]; } return total - count_root_bytes; @@ -1806,7 +2056,7 @@ static uptr total_size_so_far() { static uptr target_generation_space_so_far() { IGEN g = target_generation; ISPC s; - uptr sz = S_G.phantom_sizes[g]; + uptr sz = S_G.bytesof[g][countof_phantom]; for (s = 0; s <= max_real_space; s++) { sz += S_G.bytes_of_space[s][g]; @@ -1876,12 +2126,10 @@ static void push_measure(ptr p) if (!si) return; - if (si->space & space_old) { + if (si->old_space) { /* We must be in a GC--measure fusion, so switch back to GC */ - if (!locked(si, p)) { - relocate(&p) - return; - } + relocate_help_help(&p, p, si) + return; } if (si->generation > max_measure_generation) @@ -1922,7 +2170,7 @@ static void push_measure(ptr p) static void measure_add_stack_size(ptr stack, uptr size) { seginfo *si = SegInfo(ptr_get_segment(stack)); - if (!(si->space & space_old) + if (!(si->old_space) && (si->generation <= max_measure_generation) && (si->generation >= min_measure_generation)) measure_total += size; @@ -1952,7 +2200,7 @@ static void check_ephemeron_measure(ptr pe) { if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && (si->generation <= max_measure_generation) && (si->generation >= min_measure_generation) - && (!(si->space & space_old) || !FORWARDEDP(p, si)) + && (!(si->old_space) || !FORWARDEDP(p, si)) && (measure_unreached(si, p) || (si->counting_mask && (si->counting_mask[segment_bitmap_byte(p)] & segment_bitmap_bit(p))))) { diff --git a/c/gcwrapper.c b/c/gcwrapper.c index 60ec3872cd..06a9309674 100644 --- a/c/gcwrapper.c +++ b/c/gcwrapper.c @@ -17,8 +17,6 @@ #include "system.h" /* locally defined functions */ -static IBOOL memqp PROTO((ptr x, ptr ls)); -static IBOOL remove_first_nomorep PROTO((ptr x, ptr *pls, IBOOL look)); static void segment_tell PROTO((uptr seg)); static void check_heap_dirty_msg PROTO((char *msg, ptr *x)); static IBOOL dirty_listedp PROTO((seginfo *x, IGEN from_g, IGEN to_g)); @@ -50,11 +48,14 @@ void S_gc_init() { for (g = 0; g <= static_generation; g++) { S_G.guardians[g] = Snil; + S_G.locked_objects[g] = Snil; + S_G.unlocked_objects[g] = Snil; } S_G.max_nonstatic_generation = S_G.new_max_nonstatic_generation = S_G.min_free_gen = - S_G.new_min_free_gen = default_max_nonstatic_generation; + S_G.new_min_free_gen = + S_G.min_mark_gen = default_max_nonstatic_generation; for (g = 0; g <= static_generation; g += 1) { for (i = 0; i < countof_types; i += 1) { @@ -133,6 +134,8 @@ void S_gc_init() { S_G.countof_size[countof_stencil_vector] = 0; INITVECTIT(S_G.countof_names, countof_record) = S_intern((const unsigned char *)"record"); S_G.countof_size[countof_record] = 0; + INITVECTIT(S_G.countof_names, countof_phantom) = S_intern((const unsigned char *)"phantom"); + S_G.countof_size[countof_phantom] = 0; for (i = 0; i < countof_types; i += 1) { if (Svector_ref(S_G.countof_names, i) == FIX(0)) { fprintf(stderr, "uninitialized countof_name at index %d\n", i); @@ -167,6 +170,60 @@ void S_set_minfreegen(IGEN g) { } } +IGEN S_minmarkgen(void) { + return S_G.min_mark_gen; +} + +void S_set_minmarkgen(IGEN g) { + S_G.min_mark_gen = g; +} + +void S_immobilize_object(x) ptr x; { + seginfo *si; + + if (IMMEDIATE(x)) + si = NULL; + else + si = MaybeSegInfo(ptr_get_segment(x)); + + if ((si != NULL) && (si->generation != static_generation)) { + tc_mutex_acquire() + + /* Try a little to to support cancellation of segment-level + * immobilzation --- but we don't try too hard */ + if (si->must_mark < MUST_MARK_INFINITY) + si->must_mark++; + + /* Note: for `space_new`, `must_mark` doesn't really mean all + objects must be marked; only those in the locked list must be + marked. Non-locked objects on `space_new` cannot be immobilized. */ + + tc_mutex_release() + } +} + +void S_mobilize_object(x) ptr x; { + seginfo *si; + + if (IMMEDIATE(x)) + si = NULL; + else + si = MaybeSegInfo(ptr_get_segment(x)); + + if ((si != NULL) && (si->generation != static_generation)) { + tc_mutex_acquire() + + if (si->must_mark == 0) + S_error_abort("S_mobilize_object(): object was definitely not immobilzed"); + + /* See S_immobilize_object() about this vague try at canceling immobilation: */ + if (si->must_mark < MUST_MARK_INFINITY) + --si->must_mark; + + tc_mutex_release() + } +} + static IBOOL memqp(x, ls) ptr x, ls; { for (;;) { if (ls == Snil) return 0; @@ -202,7 +259,7 @@ IBOOL Slocked_objectp(x) ptr x; { tc_mutex_acquire() ans = 0; - for (ls = si->locked_objects; ls != Snil; ls = Scdr(ls)) { + for (ls = S_G.locked_objects[g]; ls != Snil; ls = Scdr(ls)) { if (x == Scar(ls)) { ans = 1; break; @@ -215,18 +272,14 @@ IBOOL Slocked_objectp(x) ptr x; { } ptr S_locked_objects(void) { - IGEN g; ptr ans; ptr ls; ISPC s; seginfo *si; + IGEN g; ptr ans; ptr ls; tc_mutex_acquire() ans = Snil; for (g = 0; g <= static_generation; INCRGEN(g)) { - for (s = 0; s <= max_real_space; s += 1) { - for (si = S_G.occupied_segments[s][g]; si != NULL; si = si->next) { - for (ls = si->locked_objects; ls != Snil; ls = Scdr(ls)) { - ans = Scons(Scar(ls), ans); - } - } + for (ls = S_G.locked_objects[g]; ls != Snil; ls = Scdr(ls)) { + ans = Scons(Scar(ls), ans); } } @@ -238,43 +291,44 @@ ptr S_locked_objects(void) { void Slock_object(x) ptr x; { seginfo *si; IGEN g; - tc_mutex_acquire() - /* weed out pointers that won't be relocated */ if (!IMMEDIATE(x) && (si = MaybeSegInfo(ptr_get_segment(x))) != NULL && (g = si->generation) != static_generation) { + tc_mutex_acquire() S_pants_down += 1; + /* immobilize */ + if (si->must_mark < MUST_MARK_INFINITY) + si->must_mark++; /* add x to locked list. remove from unlocked list */ - si->locked_objects = S_cons_in((g == 0 ? space_new : space_impure), g, x, si->locked_objects); + S_G.locked_objects[g] = S_cons_in((g == 0 ? space_new : space_impure), g, x, S_G.locked_objects[g]); if (S_G.enable_object_counts) { if (g != 0) S_G.countof[g][countof_pair] += 1; } - if (si->space & space_locked) - (void)remove_first_nomorep(x, &si->unlocked_objects, 0); + (void)remove_first_nomorep(x, &S_G.unlocked_objects[g], 0); S_pants_down -= 1; + tc_mutex_release() } - - tc_mutex_release() } void Sunlock_object(x) ptr x; { seginfo *si; IGEN g; - tc_mutex_acquire() - if (!IMMEDIATE(x) && (si = MaybeSegInfo(ptr_get_segment(x))) != NULL && (g = si->generation) != static_generation) { + tc_mutex_acquire() S_pants_down += 1; + /* mobilize, if we haven't lost track */ + if (si->must_mark < MUST_MARK_INFINITY) + --si->must_mark; /* remove first occurrence of x from locked list. if there are no others, add x to unlocked list */ - if (remove_first_nomorep(x, &si->locked_objects, si->space & space_locked)) { - si->unlocked_objects = S_cons_in((g == 0 ? space_new : space_impure), g, x, si->unlocked_objects); + if (remove_first_nomorep(x, &S_G.locked_objects[g], (si->space == space_new) && (si->generation > 0))) { + S_G.unlocked_objects[g] = S_cons_in((g == 0 ? space_new : space_impure), g, x, S_G.unlocked_objects[g]); if (S_G.enable_object_counts) { if (g != 0) S_G.countof[g][countof_pair] += 1; } } S_pants_down -= 1; + tc_mutex_release() } - - tc_mutex_release() } ptr s_help_unregister_guardian(ptr *pls, ptr tconc, ptr result) { @@ -406,6 +460,10 @@ ptr S_object_backreferences(void) { return ls; } +seginfo *S_ptr_seginfo(ptr p) { + return MaybeSegInfo(ptr_get_segment(p)); +} + /* Scompact_heap(). Compact into as few O/S chunks as possible and * move objects into static generation */ @@ -446,13 +504,12 @@ static void segment_tell(seg) uptr seg; { } else { printf(" generation=%d", si->generation); s = si->space; - s1 = si->space & ~(space_old|space_locked); + s1 = si->space; if (s1 < 0 || s1 > max_space) printf(" space-bogus (%d)", s); else { printf(" space-%s", spacename[s1]); - if (s & space_old) printf(" oldspace"); - if (s & space_locked) printf(" locked"); + if (si->old_space) printf(" oldspace"); } printf("\n"); } @@ -567,8 +624,10 @@ void S_check_heap(aftergc) IBOOL aftergc; { S_checkheap_errors += 1; printf("!!! unexpected generation %d segment %#tx in space_new\n", g, (ptrdiff_t)seg); } - } else if (s == space_impure || s == space_symbol || s == space_pure || s == space_weakpair /* || s == space_ephemeron */) { - /* out of date: doesn't handle space_port, space_continuation, space_code, space_pure_typed_object, space_impure_record */ + } else if (s == space_impure || s == space_symbol || s == space_pure || s == space_weakpair || s == space_ephemeron + || s == space_immobile_impure || s == space_count_pure || s == space_count_impure || s == space_closure) { + /* doesn't handle: space_port, space_continuation, space_code, space_pure_typed_object, + space_impure_record, or impure_typed_object */ nl = (ptr *)S_G.next_loc[s][g]; /* check for dangling references */ @@ -576,23 +635,43 @@ void S_check_heap(aftergc) IBOOL aftergc; { pp2 = (ptr *)build_ptr(seg + 1, 0); if (pp1 <= nl && nl < pp2) pp2 = nl; - while (pp1 != pp2) { - seginfo *psi; ISPC ps; - p = *pp1; - if (p == forward_marker) break; - if (!IMMEDIATE(p) && (psi = MaybeSegInfo(ptr_get_segment(p))) != NULL && ((ps = psi->space) & space_old || ps == space_empty)) { - S_checkheap_errors += 1; - printf("!!! dangling reference at %#tx to %#tx\n", (ptrdiff_t)pp1, (ptrdiff_t)p); - printf("from: "); segment_tell(seg); - printf("to: "); segment_tell(ptr_get_segment(p)); - } - pp1 += 1; + while (pp1 < pp2) { + if (!si->marked_mask || (si->marked_mask[segment_bitmap_byte(pp1)] & segment_bitmap_bit(pp1))) { + int a; + for (a = 0; (a < ptr_alignment) && (pp1 < pp2); a++) { +#define in_ephemeron_pair_part(pp1, seg) ((((uptr)(pp1) - (uptr)build_ptr(seg, 0)) % size_ephemeron) < size_pair) + if ((s == space_ephemeron) && !in_ephemeron_pair_part(pp1, seg)) { + /* skip non-pair part of ephemeron */ + } else { + p = *pp1; + if (p == forward_marker) { + pp1 = pp2; /* break out of outer loop */ + break; + } else if (!IMMEDIATE(p)) { + seginfo *psi = MaybeSegInfo(ptr_get_segment(p)); + if (psi != NULL) { + if ((psi->space == space_empty) + || psi->old_space + || (psi->marked_mask && !(psi->marked_mask[segment_bitmap_byte(p)] & segment_bitmap_bit(p)))) { + S_checkheap_errors += 1; + printf("!!! dangling reference at %#tx to %#tx\n", (ptrdiff_t)pp1, (ptrdiff_t)p); + printf("from: "); segment_tell(seg); + printf("to: "); segment_tell(ptr_get_segment(p)); + } + } + } + } + pp1 += 1; + } + } else + pp1 += ptr_alignment; } /* verify that dirty bits are set appropriately */ /* out of date: doesn't handle space_impure_record, space_port, and maybe others */ /* also doesn't check the SYMCODE for symbols */ - if (s == space_impure || s == space_symbol || s == space_weakpair /* || s == space_ephemeron */) { + if (s == space_impure || s == space_symbol || s == space_weakpair || s == space_ephemeron + || s == space_immobile_impure || s == space_closure) { found_eos = 0; pp2 = pp1 = build_ptr(seg, 0); for (d = 0; d < cards_per_segment; d += 1) { @@ -617,40 +696,57 @@ void S_check_heap(aftergc) IBOOL aftergc; { #endif dirty = 0xff; - while (pp1 != pp2) { - seginfo *psi; - p = *pp1; - - if (p == forward_marker) { - found_eos = 1; - break; - } - if (!IMMEDIATE(p) && (psi = MaybeSegInfo(ptr_get_segment(p))) != NULL && (pg = psi->generation) < g) { - if (pg < dirty) dirty = pg; - if (si->dirty_bytes[d] > pg) { - S_checkheap_errors += 1; - check_heap_dirty_msg("!!! INVALID", pp1); + while (pp1 < pp2) { + if (!si->marked_mask || (si->marked_mask[segment_bitmap_byte(pp1)] & segment_bitmap_bit(pp1))) { + int a; + for (a = 0; (a < ptr_alignment) && (pp1 < pp2); a++) { + if ((s == space_ephemeron) && !in_ephemeron_pair_part(pp1, seg)) { + /* skip non-pair part of ephemeron */ + } else { + p = *pp1; + + if (p == forward_marker) { + found_eos = 1; + pp1 = pp2; + break; + } else if (!IMMEDIATE(p)) { + seginfo *psi = MaybeSegInfo(ptr_get_segment(p)); + if ((psi != NULL) && ((pg = psi->generation) < g)) { + if (pg < dirty) dirty = pg; + if (si->dirty_bytes[d] > pg) { + S_checkheap_errors += 1; + check_heap_dirty_msg("!!! INVALID", pp1); + } else if (checkheap_noisy) + check_heap_dirty_msg("... ", pp1); + } + } + } + pp1 += 1; } - else if (checkheap_noisy) - check_heap_dirty_msg("... ", pp1); + } else { + pp1 += ptr_alignment; } - pp1 += 1; } + if (checkheap_noisy && si->dirty_bytes[d] < dirty) { /* sweep_dirty won't sweep, and update dirty byte, for cards with dirty pointers to segments older than the maximum copyied generation, so we can get legitimate conservative dirty bytes even after gc */ printf("... Conservative dirty byte %x (%x) %sfor segment %#tx card %d ", - si->dirty_bytes[d], dirty, - (aftergc ? "after gc " : ""), - (ptrdiff_t)seg, d); + si->dirty_bytes[d], dirty, + (aftergc ? "after gc " : ""), + (ptrdiff_t)seg, d); segment_tell(seg); } } } } - if (aftergc && s != space_empty && !(s & space_locked) && (g == 0 || (s != space_impure && s != space_symbol && s != space_port && s != space_weakpair && s != space_ephemeron && s != space_impure_record))) { + if (aftergc + && (s != space_empty) + && (g == 0 + || (s != space_impure && s != space_symbol && s != space_port && s != space_weakpair && s != space_ephemeron + && s != space_impure_record && s != space_immobile_impure && s != space_count_impure && s != space_closure))) { for (d = 0; d < cards_per_segment; d += 1) { if (si->dirty_bytes[d] != 0xff) { S_checkheap_errors += 1; @@ -680,7 +776,6 @@ static void check_dirty_space(ISPC s) { for (from_g = 0; from_g <= static_generation; from_g += 1) { for (si = S_G.occupied_segments[s][from_g]; si != NULL; si = si->next) { - if (si->space & space_locked) continue; min_to_g = 0xff; for (d = 0; d < cards_per_segment; d += 1) { to_g = si->dirty_bytes[d]; @@ -720,7 +815,7 @@ static void check_dirty() { } } else { while (si != NULL) { - ISPC s = si->space & ~space_locked; + ISPC s = si->space; IGEN g = si->generation; IGEN mingval = si->min_dirty_byte; if (g != from_g) { @@ -798,6 +893,8 @@ ptr S_do_gc(IGEN mcg, IGEN tg, ptr count_roots) { } } S_G.guardians[new_g] = S_G.guardians[old_g]; S_G.guardians[old_g] = Snil; + S_G.locked_objects[new_g] = S_G.locked_objects[old_g]; S_G.locked_objects[old_g] = Snil; + S_G.unlocked_objects[new_g] = S_G.unlocked_objects[old_g]; S_G.unlocked_objects[old_g] = Snil; S_G.buckets_of_generation[new_g] = S_G.buckets_of_generation[old_g]; S_G.buckets_of_generation[old_g] = NULL; if (S_G.enable_object_counts) { INT i; ptr ls; @@ -880,7 +977,6 @@ ptr S_do_gc(IGEN mcg, IGEN tg, ptr count_roots) { return result; } - ptr S_gc(ptr tc, IGEN mcg, IGEN tg, ptr count_roots) { if (tg == static_generation || S_G.enable_object_counts || S_G.enable_object_backreferences diff --git a/c/globals.h b/c/globals.h index 0eaa26bd87..0da2669888 100644 --- a/c/globals.h +++ b/c/globals.h @@ -123,10 +123,13 @@ EXTERN struct S_G_struct { /* gc.c */ ptr guardians[static_generation+1]; + ptr locked_objects[static_generation+1]; + ptr unlocked_objects[static_generation+1]; IGEN min_free_gen; IGEN new_min_free_gen; IGEN max_nonstatic_generation; IGEN new_max_nonstatic_generation; + IGEN min_mark_gen; uptr countof[static_generation+1][countof_types]; uptr bytesof[static_generation+1][countof_types]; uptr gctimestamp[static_generation+1]; @@ -135,7 +138,6 @@ EXTERN struct S_G_struct { ptr static_id; ptr countof_names; ptr gcbackreference[static_generation+1]; - uptr phantom_sizes[static_generation+1]; IGEN prcgeneration; uptr bytes_finalized; diff --git a/c/prim.c b/c/prim.c index 705520b1f3..d5edf871b0 100644 --- a/c/prim.c +++ b/c/prim.c @@ -189,6 +189,8 @@ void S_prim_init() { Sforeign_symbol("(cs)maxgen", (void *)S_maxgen); Sforeign_symbol("(cs)set_maxgen", (void *)S_set_maxgen); Sforeign_symbol("(cs)minfreegen", (void *)S_minfreegen); + Sforeign_symbol("(cs)set_minmarkgen", (void *)S_set_minmarkgen); + Sforeign_symbol("(cs)minmarkgen", (void *)S_minmarkgen); Sforeign_symbol("(cs)set_minfreegen", (void *)S_set_minfreegen); Sforeign_symbol("(cs)enable_object_counts", (void *)S_enable_object_counts); Sforeign_symbol("(cs)set_enable_object_counts", (void *)S_set_enable_object_counts); @@ -216,6 +218,8 @@ static void s_instantiate_code_object() { new = S_code(tc, CODETYPE(old), CODELEN(old)); tc_mutex_release() + S_immobilize_object(new); + oldreloc = CODERELOC(old); size = RELOCSIZE(oldreloc); newreloc = S_relocation_table(size); diff --git a/c/prim5.c b/c/prim5.c index 2b8213386a..cb23767441 100644 --- a/c/prim5.c +++ b/c/prim5.c @@ -35,6 +35,9 @@ static ptr s_fltofx PROTO((ptr x)); static ptr s_weak_pairp PROTO((ptr p)); static ptr s_ephemeron_cons PROTO((ptr car, ptr cdr)); static ptr s_ephemeron_pairp PROTO((ptr p)); +static ptr s_box_immobile PROTO((ptr p)); +static ptr s_make_immobile_vector PROTO((uptr len, ptr fill)); +static ptr s_make_immobile_bytevector PROTO((uptr len)); static ptr s_oblist PROTO((void)); static ptr s_bigoddp PROTO((ptr n)); static ptr s_float PROTO((ptr x)); @@ -176,7 +179,7 @@ static ptr s_fltofx(x) ptr x; { static ptr s_weak_pairp(p) ptr p; { seginfo *si; - return Spairp(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && (si->space & ~space_locked) == space_weakpair ? Strue : Sfalse; + return Spairp(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && si->space == space_weakpair ? Strue : Sfalse; } static ptr s_ephemeron_cons(car, cdr) ptr car, cdr; { @@ -193,7 +196,35 @@ static ptr s_ephemeron_cons(car, cdr) ptr car, cdr; { static ptr s_ephemeron_pairp(p) ptr p; { seginfo *si; - return Spairp(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && (si->space & ~space_locked) == space_ephemeron ? Strue : Sfalse; + return Spairp(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && si->space == space_ephemeron ? Strue : Sfalse; +} + +static ptr s_box_immobile(p) ptr p; { + ptr b = S_box2(p, 1); + S_immobilize_object(b); + return b; +} + +static ptr s_make_immobile_bytevector(uptr len) { + ptr b = S_bytevector2(len, 1); + S_immobilize_object(b); + return b; +} + +static ptr s_make_immobile_vector(uptr len, ptr fill) { + ptr v; + uptr i; + + tc_mutex_acquire() + v = S_vector_in(space_immobile_impure, 0, len); + tc_mutex_release() + + S_immobilize_object(v); + + for (i = 0; i < len; i++) + INITVECTIT(v, i) = fill; + + return v; } static ptr s_oblist() { @@ -508,7 +539,7 @@ static void s_showalloc(IBOOL show_dump, const char *outfn) { fprintf(out, "\nMap of occupied segments:\n"); for (ls = sorted_chunks; ls != Snil; ls = Scdr(ls)) { - seginfo *si; ISPC real_s; + seginfo *si; chunk = Scar(ls); @@ -545,11 +576,9 @@ static void s_showalloc(IBOOL show_dump, const char *outfn) { } si = &chunk->sis[i]; - real_s = si->space; - s = real_s & ~(space_locked | space_old); + s = si->space; if (s < 0 || s > max_space) s = space_bogus; - spaceline[segwidth+segsprinted] = - real_s & (space_locked | space_old) ? toupper(spacechar[s]) : spacechar[s]; + spaceline[segwidth+segsprinted] = spacechar[s]; g = si->generation; genline[segwidth+segsprinted] = @@ -1414,12 +1443,12 @@ static s_thread_rv_t s_backdoor_thread_start(p) void *p; { display("backdoor thread started\n") (void) Sactivate_thread(); display("thread activated\n") - Scall0((ptr)p); + Scall0((ptr)Sunbox(p)); (void) Sdeactivate_thread(); display("thread deactivated\n") (void) Sactivate_thread(); display("thread reeactivated\n") - Scall0((ptr)p); + Scall0((ptr)Sunbox(p)); Sdestroy_thread(); display("thread destroyed\n") s_thread_return; @@ -1535,6 +1564,9 @@ void S_prim5_init() { Sforeign_symbol("(cs)s_weak_pairp", (void *)s_weak_pairp); Sforeign_symbol("(cs)s_ephemeron_cons", (void *)s_ephemeron_cons); Sforeign_symbol("(cs)s_ephemeron_pairp", (void *)s_ephemeron_pairp); + Sforeign_symbol("(cs)box_immobile", (void *)s_box_immobile); + Sforeign_symbol("(cs)make_immobile_vector", (void *)s_make_immobile_vector); + Sforeign_symbol("(cs)make_immobile_bytevector", (void *)s_make_immobile_bytevector); Sforeign_symbol("(cs)continuation_depth", (void *)S_continuation_depth); Sforeign_symbol("(cs)single_continuation", (void *)S_single_continuation); Sforeign_symbol("(cs)c_exit", (void *)c_exit); diff --git a/c/schlib.c b/c/schlib.c index 4f3c2e300d..4a73c560b4 100644 --- a/c/schlib.c +++ b/c/schlib.c @@ -216,7 +216,7 @@ void S_call_help(tc_in, singlep, lock_ts) ptr tc_in; IBOOL singlep; IBOOL lock_t the C stack and we may end up in a garbage collection */ code = CP(tc); if (Sprocedurep(code)) code = CLOSCODE(code); - Slock_object(code); + S_immobilize_object(code); CP(tc) = AC1(tc); @@ -226,7 +226,7 @@ void S_call_help(tc_in, singlep, lock_ts) ptr tc_in; IBOOL singlep; IBOOL lock_t if (lock_ts) { /* Lock a code object passed in TS, which is a more immediate caller whose return address is on the C stack */ - Slock_object(TS(tc)); + S_immobilize_object(TS(tc)); CCHAIN(tc) = Scons(Scons(jb, Scons(code,TS(tc))), CCHAIN(tc)); } else { CCHAIN(tc) = Scons(Scons(jb, Scons(code,Sfalse)), CCHAIN(tc)); @@ -293,8 +293,8 @@ void S_return() { /* error checks are done; now unlock affected code objects */ for (xp = CCHAIN(tc); ; xp = Scdr(xp)) { ptr p = CDAR(xp); - Sunlock_object(Scar(p)); - if (Scdr(p) != Sfalse) Sunlock_object(Scdr(p)); + S_mobilize_object(Scar(p)); + if (Scdr(p) != Sfalse) S_mobilize_object(Scdr(p)); if (xp == yp) break; FREEJMPBUF(CAAR(xp)); } diff --git a/c/segment.c b/c/segment.c index cef05b75de..09f87517ef 100644 --- a/c/segment.c +++ b/c/segment.c @@ -229,6 +229,9 @@ static void initialize_seginfo(seginfo *si, ISPC s, IGEN g) { si->space = s; si->generation = g; si->sorted = 0; + si->old_space = 0; + si->use_marks = 0; + si->must_mark = 0; si->min_dirty_byte = 0xff; for (d = 0; d < cards_per_segment; d += sizeof(ptr)) { iptr *dp = (iptr *)(si->dirty_bytes + d); @@ -238,9 +241,7 @@ static void initialize_seginfo(seginfo *si, ISPC s, IGEN g) { si->has_triggers = 0; si->trigger_ephemerons = 0; si->trigger_guardians = 0; - si->locked_objects = Snil; - si->unlocked_objects = Snil; - si->locked_mask = NULL; + si->marked_mask = NULL; #ifdef PRESERVE_FLONUM_EQ si->forwarded_flonums = NULL; #endif @@ -380,6 +381,9 @@ static seginfo *allocate_segments(nreq) uptr nreq; { si->space = space_empty; si->generation = 0; si->sorted = 1; /* inserting in reverse order, so emptys are always sorted */ + si->old_space = 0; + si->use_marks = 0; + si->must_mark = 0; si->next = chunk->unused_segs; chunk->unused_segs = si; } @@ -434,6 +438,10 @@ void S_resetmaxmembytes(void) { maxmembytes = membytes; } +void S_adjustmembytes(iptr amt) { + if ((membytes += amt) < maxmembytes) maxmembytes = membytes; +} + static void expand_segment_table(uptr base, uptr end, seginfo *si) { #ifdef segment_t2_bits #ifdef segment_t3_bits diff --git a/c/segment.h b/c/segment.h index 0d6c3b0210..361e083cc6 100644 --- a/c/segment.h +++ b/c/segment.h @@ -81,3 +81,4 @@ FORCEINLINE seginfo *MaybeSegInfo(uptr i) { #define SegmentSpace(i) (SegInfo(i)->space) #define SegmentGeneration(i) (SegInfo(i)->generation) +#define SegmentOldSpace(i) (SegInfo(i)->old_space) diff --git a/c/types.h b/c/types.h index 8e681192a6..5e0f0ae3e2 100644 --- a/c/types.h +++ b/c/types.h @@ -121,16 +121,22 @@ typedef int IFASLCODE; /* fasl type codes */ #define SPACE(p) SegmentSpace(ptr_get_segment(p)) #define GENERATION(p) SegmentGeneration(ptr_get_segment(p)) +#define OLDSPACE(p) SegmentOldSpace(ptr_get_segment(p)) #define ptr_align(size) (((size)+byte_alignment-1) & ~(byte_alignment-1)) +#define MUST_MARK_INFINITY 3 + /* The inlined implementation of primitives like `weak-pair?` rely on the first two fields of `seginfo`: */ typedef struct _seginfo { unsigned char space; /* space the segment is in */ unsigned char generation; /* generation the segment is in */ - unsigned char sorted : 1; /* sorted indicator---possibly to be incorporated into space flags? */ + unsigned char old_space : 1; /* set during GC to indcate space being collected */ + unsigned char use_marks : 1; /* set during GC to indicate space to mark in place instead of copy */ + unsigned char sorted : 1; /* sorted indicator */ unsigned char has_triggers : 1; /* set if trigger_ephemerons or trigger_guardians is set */ + unsigned char must_mark : 2; /* a form of locking, where 3 counts as "infinite" */ octet min_dirty_byte; /* dirty byte for full segment, effectively min(dirty_bytes) */ uptr number; /* the segment number */ struct _chunkinfo *chunk; /* the chunk this segment belongs to */ @@ -139,9 +145,8 @@ typedef struct _seginfo { struct _seginfo *dirty_next; /* pointer to the next seginfo on the DirtySegments list */ ptr trigger_ephemerons; /* ephemerons to re-check if object in segment is copied out */ ptr trigger_guardians; /* guardians to re-check if object in segment is copied out */ - ptr locked_objects; /* list of objects (including duplicates) for locked in this segment */ - ptr unlocked_objects; /* list of objects (no duplicates) for formerly locked */ - octet *locked_mask; /* bitmap of locked objects, used only during GC */ + octet *marked_mask; /* bitmap of live objects for a segment in "compacting" mode */ + uptr marked_count; /* number of marked bytes in segment */ #ifdef PRESERVE_FLONUM_EQ octet *forwarded_flonums; /* bitmap of flonums whose payload is a forwarding pointer */ #endif diff --git a/c/vfasl.c b/c/vfasl.c index 1cd45421b1..b235ef1172 100644 --- a/c/vfasl.c +++ b/c/vfasl.c @@ -252,7 +252,7 @@ ptr S_vfasl(ptr bv, void *stream, iptr offset, iptr input_len) if (sz > 0) { if ((s == vspace_reloc) && !S_G.retain_static_relocation) { thread_find_room(tc, typemod, sz, vspaces[s]) - } else { + } else { find_room(vspace_spaces[s], static_generation, typemod, sz, vspaces[s]) } if (S_fasl_stream_read(stream, vspaces[s], sz) < 0) diff --git a/csug/foreign.stex b/csug/foreign.stex index 5807378658..879bd12d03 100644 --- a/csug/foreign.stex +++ b/csug/foreign.stex @@ -1069,14 +1069,14 @@ the address of the entry point within the code object. (The C-callable library function \scheme{Sforeign_callable_entry_point}, described in Section~\ref{SECTFOREIGNCLIB}, may be used to obtain the entry point as well.) -This is an implicit pointer into a Scheme object, and -in many cases, it is necessary to lock the code object -(using \index{\scheme{lock-object}}\scheme{lock-object}) -before converting it into an entry point -to prevent Scheme's storage management system from -relocating or destroying the code object, e.g., when the entry point is +This is an implicit pointer into an immobile Scheme object, so +it will not be relocated by the storage management system, but +it may be reclaimed if the code object becomes unreachable on the Scheme +side; lock the code object (using \index{\scheme{lock-object}}\scheme{lock-object}) +or otherwise retain it if the entry point is, for example, registered as a callback and retained in the ``C'' side indefinitely. + The following code creates a foreign-callable code object, locks the code object, and returns the entry point. @@ -1090,9 +1090,9 @@ the code object, and returns the entry point. \endschemedisplay \noindent -Unless the entry point is intended to be permanent, a pointer to the -code object returned by \scheme{foreign-callable} should be retained -so that it can be unlocked when no longer needed. +Unless the entry point is intended to be permanent, however, a pointer +to the code object returned by \scheme{foreign-callable} should be retained, +in which case locking is unnecessary. Mixed use of \scheme{foreign-callable} and \scheme{foreign-procedure} may result in nesting of foreign and Scheme calls, and this @@ -1871,8 +1871,8 @@ Thus, \scheme{make-ftype-pointer} with a function ftype is an alternative to \scheme{foreign-callable} for creating C-callable wrappers for Scheme procedures. -Since all Scheme objects, including code objects, can be relocated or -even reclaimed by the garbage collector the foreign-callable code object +Since the foreign-callable code object can be reclaimed by the garbage +collector if it is not otherwise referenced, the implicit foreign-callable's code object is automatically locked, as if via \scheme{lock-object}, before it is embedded in the ftype pointer. The code object should be unlocked after its last use from C, @@ -1890,7 +1890,10 @@ to \scheme{unlock-object}: (ftype-pointer-address fact-fptr))) \endschemedisplay -Once unlocked, the ftype pointer should not be used again, unless +Even after the code object is unlocked, the code code will remain +immobile as long as a result of \scheme{foreign-callable-code-object} +is retained. However, if only the ftype pointer object is retained, +then the ftype pointer should not be used again unless it is relocked, e.g., via: \schemedisplay diff --git a/csug/smgmt.stex b/csug/smgmt.stex index 8db85446ed..6a5363eacc 100644 --- a/csug/smgmt.stex +++ b/csug/smgmt.stex @@ -330,6 +330,26 @@ When \scheme{collect-maximum-generation} is set to a new value \var{g}, if (a) the two parameters have the same value before the change, or (b) \scheme{release-minimum-generation} has a value greater than \var{g}. +%---------------------------------------------------------------------------- +\entryheader +\formdef{in-place-minimum-generation}{\categoryglobalparameter}{in-place-minimum-generation} +\listlibraries +\endentryheader + +This parameter determines when the storage-management system attempts +to trade long-term space usage for the benefit of collection time and +short-term space usage. When performing a collection at the generation +at least as large as this parameter's value, objects already residing +at the generation are kept in place---unless the objects are in a +memory region where previously keeping them in place resulted in too +much fragmentation. + +Typically, the value of \scheme{release-minimum-generation} should +match the value of the \scheme{collect-maximum-generation} parameter, +but the value of this parameter can be lower to move objects even less +frequently, or it can be higher to disable attempts to keep otherwise +mobile objects in place. + %---------------------------------------------------------------------------- \entryheader \formdef{heap-reserve-ratio}{\categoryglobalparameter}{heap-reserve-ratio} @@ -348,6 +368,19 @@ Setting it to a smaller value may result in a smaller average virtual memory footprint, while setting it to a larger value may result in fewer calls into the operating system to request and free memory space. +%---------------------------------------------------------------------------- +\entryheader +\formdef{keep-live}{\categoryprocedure}{(keep-live \var{v})} +\returns unspecified +\listlibraries +\endentryheader + +\noindent +Ensures that the value produced by \var{v} is retained by the store +manager until the \scheme{keep-live} call is performed. This function +can be particularly useful for ensuring that an immobile object +remains in place. + \section{Weak Pairs, Ephemeron Pairs, and Guardians\label{SECTGUARDWEAKPAIRS}} @@ -984,6 +1017,53 @@ by the collector, including immediate values, such as fixnums, booleans, and characters, and objects that have been made static. +\section{Immobile Objects\label{SECTSMGMTIMMOBILE}} + +Like a locked object, an \emph{immobile} object will not be relocated by +the storage manager. Unlike a locked object, and immobile object will +be reclaimed by the storage manager if it is unreachable. +Foreign-callable code objects are immobile, as are objects allocated +by functions that specifically create immobile objects. + +%---------------------------------------------------------------------------- +\entryheader +\formdef{box-immobile}{\categoryprocedure}{(box-immobile \var{obj})} +\returns a box +\listlibraries +\endentryheader + +\noindent +Like \scheme{box}, but creates a box that will not be relocated in memory +by the storage management system until it is reclaimed. + + +%---------------------------------------------------------------------------- +\entryheader +\formdef{make-immobile-vector}{\categoryprocedure}{(make-immobile-vector \var{n})} +\formdef{make-immobile-vector}{\categoryprocedure}{(make-immobile-vector \var{n} \var{obj})} +\returns a vector +\listlibraries +\endentryheader + +\noindent +Like \scheme{make-vector}, but creates a vector that will not be relocated +in memory by the storage management system until it is reclaimed. + + +%---------------------------------------------------------------------------- +\entryheader +\formdef{make-immobile-bytevector}{\categoryprocedure}{(make-immobile-bytevector \var{n})} +\formdef{make-immobile-bytevector}{\categoryprocedure}{(make-immobile-bytevector \var{n} \var{byte})} +\returns a vector +\listlibraries +\endentryheader + +\noindent +Like \scheme{make-bytevector}, but creates a bytevector that will not be relocated +in memory by the storage management system until it is reclaimed. + + + \section{Phantom Bytevectors\label{SECTSMGMTPHANTOM}} \index{phamtom bytevectors}A \emph{phantom bytevector} represents @@ -1016,7 +1096,7 @@ allocation. The value \var{n} must reflect actual allocation in the sense of consuming a portion of the process's address space. Claiming significantly more bytes than are actually allocated introduces the -possibility of overflow within the store management system's +possibility of overflow within the storage management system's calculations. %---------------------------------------------------------------------------- diff --git a/makefiles/Mf-install.in b/makefiles/Mf-install.in index b1d5cab17e..11c191c324 100644 --- a/makefiles/Mf-install.in +++ b/makefiles/Mf-install.in @@ -62,7 +62,7 @@ InstallLZ4Target= # no changes should be needed below this point # ############################################################################### -Version=csv9.5.3.26 +Version=csv9.5.3.27 Include=boot/$m PetiteBoot=boot/$m/petite.boot SchemeBoot=boot/$m/scheme.boot diff --git a/mats/4.ms b/mats/4.ms index 1505943ba4..a6ad005baf 100644 --- a/mats/4.ms +++ b/mats/4.ms @@ -4126,7 +4126,7 @@ (let* ([g (make-guardian)] [x (list 'a 'b)]) (g x) (collect 0 0) - (#%$keep-live x) + (keep-live x) (g))) #f) ;; same for ordered: @@ -4134,7 +4134,7 @@ (let* ([g (make-guardian #t)] [x (list 'a 'b)]) (g x) (collect 0 0) - (#%$keep-live x) + (keep-live x) (g))) #f) diff --git a/mats/Mf-base b/mats/Mf-base index 78a28d3d66..70cfc3e386 100644 --- a/mats/Mf-base +++ b/mats/Mf-base @@ -92,6 +92,10 @@ cgr = $(defaultcgr) defaultcmg = (collect-maximum-generation) cmg = $(defaultcmg) +# ipmg is the value to which in-place-minimum-generation is set. +defaultipmg = (in-place-minimum-generation) +ipmg = $(defaultipmg) + # rmg is the value to which release-minimum-generation is set. defaultrmg = (release-minimum-generation) rmg = $(defaultrmg) @@ -161,6 +165,7 @@ $(objdir)/%.mo : %.ms mat.so '(collect-trip-bytes ${ctb})'\ '(collect-generation-radix ${cgr})'\ '(collect-maximum-generation ${cmg})'\ + '(in-place-minimum-generation ${ipmg})'\ '(enable-object-counts #${eoc})'\ '(commonization-level ${cl})'\ '(compile-interpret-simple #${cis})'\ @@ -185,6 +190,7 @@ $(objdir)/%.mo : %.ms mat.so '(collect-trip-bytes ${ctb})'\ '(collect-generation-radix ${cgr})'\ '(collect-maximum-generation ${cmg})'\ + '(in-place-minimum-generation ${ipmg})'\ '(enable-object-counts #${eoc})'\ '(commonization-level ${cl})'\ '(compile-interpret-simple #${cis})'\ @@ -359,6 +365,7 @@ script.all$o makescript$o: '(collect-trip-bytes ${ctb})'\ '(collect-generation-radix ${cgr})'\ '(collect-maximum-generation ${cmg})'\ + '(in-place-minimum-generation ${ipmg})'\ '(enable-object-counts #${eoc})'\ '(commonization-level ${cl})'\ '(compile-interpret-simple #${cis})'\ diff --git a/mats/foreign.ms b/mats/foreign.ms index 7e2b7ff552..92e9113967 100644 --- a/mats/foreign.ms +++ b/mats/foreign.ms @@ -2002,6 +2002,19 @@ ) (mat foreign-callable + (begin + ;; We don't have to use `lock-object` on the result of a `foreign-callable`, + ;; because it is immobile. We have to keep it live, though. + (define-syntax with-object-kept-live + (lambda (x) + (syntax-case x () + [(_ id expr) + (identifier? #'id) + #'(let ([v expr]) + (keep-live id) + v)]))) + #t) + (error? ; spam is not a procedure (foreign-callable 'spam () void)) (error? ; spam is not a procedure @@ -2085,19 +2098,16 @@ (define args3 (list #f #\newline -51293 3.1415 2.5 #f)) (let () (define addr - (begin - (lock-object Fargtest) - (foreign-callable-entry-point Fargtest))) - (dynamic-wind - void - (lambda () + (foreign-callable-entry-point Fargtest)) + (let () (collect (collect-maximum-generation)) (collect (collect-maximum-generation)) - (and + (with-object-kept-live + Fargtest + (and (equal? (apply Sargtest addr args1) (reverse args1)) (equal? (apply Sargtest addr args2) (reverse args2)) - (equal? (apply Sargtest addr args3) (reverse args3)))) - (lambda () (unlock-object Fargtest))))) + (equal? (apply Sargtest addr args3) (reverse args3))))))) (let () (define Fargtest2 (foreign-callable @@ -2114,19 +2124,16 @@ (define args3 (list -7500 #x987654 #\? +inf.0 3210 #\7)) (let () (define addr - (begin - (lock-object Fargtest2) - (foreign-callable-entry-point Fargtest2))) - (dynamic-wind - void - (lambda () + (foreign-callable-entry-point Fargtest2)) + (let () (collect (collect-maximum-generation)) (collect (collect-maximum-generation)) - (and + (with-object-kept-live + Fargtest2 + (and (equal? (apply Sargtest2 addr args1) (reverse args1)) (equal? (apply Sargtest2 addr args2) (reverse args2)) - (equal? (apply Sargtest2 addr args3) (reverse args3)))) - (lambda () (unlock-object Fargtest2))))) + (equal? (apply Sargtest2 addr args3) (reverse args3))))))) (let () (define Frvtest_int32 (foreign-callable @@ -2229,9 +2236,9 @@ (let ([x 5]) (define call-twice (foreign-procedure "call_twice" (void* int int) void)) (let ([co (foreign-callable (lambda (y) (set! x (+ x y))) (int) void)]) - (lock-object co) - (call-twice (foreign-callable-entry-point co) 7 31) - (unlock-object co)) + (with-object-kept-live + co + (call-twice (foreign-callable-entry-point co) 7 31))) x) 43) (equal? @@ -2247,7 +2254,6 @@ (define callback (lambda (p) (let ([code (foreign-callable p (char) void)]) - (lock-object code) (foreign-callable-entry-point code)))) (let () (define ouch @@ -2278,9 +2284,9 @@ ; this form needs to be after the preceding form and not part of it, so that when ; we lock code we don't also lock the code object created by foreign-procedure (begin - (lock-object code) - ((foreign-procedure (foreign-callable-entry-point code) () scheme-object)) - (unlock-object code) + (with-object-kept-live + code + ((foreign-procedure (foreign-callable-entry-point code) () scheme-object))) #t) (not (locked-object? @@ -2408,11 +2414,11 @@ (define fptr (make-ftype-pointer foo f)) (define g (ftype-ref foo () fptr)) (with-exception-handler - (lambda (c) (*k* *m*)) - (lambda () - (call/cc - (lambda (k) - (fluid-let ([*k* k]) (f $stack-depth $base-value)))))) + (lambda (c) (*k* *m*)) + (lambda () + (call/cc + (lambda (k) + (fluid-let ([*k* k]) (f $stack-depth $base-value)))))) (unlock-object (foreign-callable-code-object (ftype-pointer-address fptr))) @@ -2491,8 +2497,7 @@ (ftype-pointer-address fptr))) *m*) (+ $stack-depth $base-value))) - ;; Make sure that a callable is suitably locked, and that it's - ;; unlocked when the C stack is popped by an escape + ;; A callable isn't locked, but it's immobile (equal? (let () (define Sinvoke2 @@ -2502,9 +2507,7 @@ (define Fcons (foreign-callable (lambda (k y) - ;; Escape with locked, which should be #t - ;; because a callable is locked while it's - ;; called: + (collect) ; might crash if `Fcons` were mobile (k (locked-object? Fcons))) (scheme-object iptr) scheme-object)) @@ -2515,7 +2518,7 @@ ;; Escape from callable: (let ([v ($with-exit-proc (lambda (k) (Sinvoke2 Fcons k 5)))]) (list v (locked-object? Fcons))))) - '((#t #f) (#t #f))) + '((#f #f) (#f #f))) ;; Make sure the code pointer for a call into a ;; foreign procedure is correctly saved for locking @@ -2534,8 +2537,9 @@ (set! v (add1 v)) (loop (bitwise-arithmetic-shift-right n 1)))))) (define handler (foreign-callable work (long) void)) - (lock-object handler) - (call_many_times (foreign-callable-entry-point handler)) + (with-object-kept-live + handler + (call_many_times (foreign-callable-entry-point handler))) v) 14995143) @@ -2557,9 +2561,9 @@ (eqv? i3 2)))) (int u8* u8* u8* u8* int u8* u8* int) void)]) - (lock-object cb) - (call-with-many-args (foreign-callable-entry-point cb)) - (unlock-object cb) + (with-object-kept-live + cb + (call-with-many-args (foreign-callable-entry-point cb))) result) ) diff --git a/mats/misc.ms b/mats/misc.ms index af999a4b32..2f0466cd8b 100644 --- a/mats/misc.ms +++ b/mats/misc.ms @@ -14,7 +14,7 @@ ;;; limitations under the License. ;;; regression and other tests that don't fit somewhere more logical - + (define-syntax biglet (lambda (x) (syntax-case x () @@ -2696,6 +2696,8 @@ (time=? (cost-center-time $cc-3) (make-time 'time-duration 0 0)) ) + + (mat lock-object (begin (define $locked-objects (foreign-procedure "(cs)locked_objects" () ptr)) @@ -3042,7 +3044,7 @@ (set-car! p 'yes) (unlock-object v) (equal? '(yes . 2) (vector-ref v (sub1 N))))) -) + ) (mat eval-order (eqv? (call/cc (lambda (k) (0 (k 1)))) 1) @@ -4870,7 +4872,6 @@ (and (equal? (wrapper-procedure-data a) g) (begin (unlock-object a) #t)))) - ) (mat fasl-immutable @@ -5093,10 +5094,12 @@ (bytes-allocated) (* 2.25 $pre-allocated)) - ;; No big change to `(current-memory-bytes)` - (< (* 0.75 $pre-memory) + ;; Big change to `(current-memory-bytes)` + (< (+ (* 0.75 $pre-allocated) + $pre-memory) (current-memory-bytes) - (* 1.25 $pre-memory)) + (+ (* 1.25 $pre-memory) + $pre-memory)) ;; Same change after GC (begin @@ -5140,4 +5143,177 @@ (< (* 0.75 $pre-allocated) (bytes-allocated) (* 1.25 $pre-allocated))) -) + ) + +(mat immobile + (error? (box-immobile)) + (error? (box-immobile 1 2)) + + (error? (make-immobile-vector)) + (error? (make-immobile-vector 'a)) + (error? (make-immobile-vector -10)) + (error? (make-immobile-vector (expt 2 100))) + (error? (make-immobile-vector 10 1 2)) + + (error? (make-immobile-bytevector)) + (error? (make-immobile-bytevector 'a)) + (error? (make-immobile-byte-vector -10)) + (error? (make-immobile-bytevector (expt 2 100))) + (error? (make-immobile-bytevector 10 1024)) + (error? (make-immobile-bytevector 10 1 2)) + + (box? (box-immobile 10)) + (vector? (make-immobile-vector 10)) + (eqv? 0 (vector-ref (make-immobile-vector 10) 9)) + (bytevector? (make-immobile-bytevector 10)) + (eqv? 0 (bytevector-u8-ref (make-immobile-bytevector 10 0) 9)) + + (begin + (define (make-objects) + (let loop ([i 16]) + (cond + [(zero? i) '()] + [else + (let* ([b (box-immobile (format "box ~a" i))] + [b-addr (#%$fxaddress b)] + [v (make-immobile-vector (expt 2 i) b)] + [v-addr (#%$fxaddress v)] + [s (make-immobile-bytevector (expt 2 i) i)] + [s-addr (#%$fxaddress s)]) + (cons (list i + b b-addr + v v-addr + s s-addr) + (loop (sub1 i))))]))) + (define (check-objects l) + (let loop ([l l]) + (or (null? l) + (let-values ([(i b b-addr v v-addr s s-addr) (apply values (car l))]) + (and (equal? (format "box ~a" i) (unbox b)) + (equal? (format "box ~a" i) (unbox (vector-ref v (sub1 (vector-length v))))) + (eqv? i (bytevector-u8-ref s (sub1 (bytevector-length s)))) + (eqv? b-addr (#%$fxaddress b)) + (eqv? v-addr (#%$fxaddress v)) + (eqv? s-addr (#%$fxaddress s)) + (loop (cdr l))))))) + (define (mutate-objects l) + (let loop ([l l]) + (or (null? l) + (let-values ([(i b b-addr v v-addr s s-addr) (apply values (car l))]) + (set-box! b (format "box ~a" i)) + (vector-set! v (sub1 (vector-length v)) (box (unbox b))) + (loop (cdr l)))))) + #t) + + (with-interrupts-disabled + (let ([objs (make-objects)]) + (and (check-objects objs) + (begin + (collect 0 1) + (and + (check-objects objs) + (begin + (mutate-objects objs) + (collect 0 0) + (and + (check-objects objs) + (begin + (collect (collect-maximum-generation)) + (check-objects objs))))))))) + + (or + (not (threaded?)) + (let ([m (make-mutex)] + [c (make-condition)] + [running 4]) + (let thread-loop ([t running]) + (unless (= t 0) + (fork-thread + (lambda () + (let loop ([i 1000] [objs '()] [addrs '()]) + (cond + [(= i 0) + (mutex-acquire m) + (set! running (sub1 running)) + (condition-signal c) + (mutex-release m)] + [else + (let ([v (case (modulo i 3) + [(0) (box-immobile objs)] + [(1) (make-immobile-vector i objs)] + [(2) (make-immobile-bytevector i)])]) + (let ([objs (cons v objs)] + [addrs (cons (#%$fxaddress v) addrs)]) + (collect-rendezvous) + (let check ([objs objs] [addrs addrs]) + (unless (null? objs) + (let ([v (car objs)]) + (unless (= (#%$fxaddress v) (car addrs)) + (error 'immobile "address changed: ~s" v)) + (cond + [(box? v) + (unless (eq? (unbox v) (cdr objs)) + (error 'immobile "bad box content"))] + [(vector? v) + (let loop ([j 0]) + (unless (= j (vector-length v)) + (unless (eq? (cdr objs) (vector-ref v j)) + (error 'immobile "bad vector content")) + (loop (add1 j))))] + [(bytevector? v) + (void)] + [else + (error 'immobile "bad object: ~s" v)])) + (check (cdr objs) (cdr addrs)))) + (loop (sub1 i) objs addrs)))])))) + (thread-loop (sub1 t)))) + (mutex-acquire m) + (let loop () + (unless (= running 0) + (condition-wait c m) + (loop))) + (mutex-release m) + #t)) + + ) + +(mat compacting + ;; try to provoke the GC into putting a record into marked + ;; (insteda of copied) space and check the write barrier there + (let loop ([N 2]) + (or (= N 8192) + (let sel-loop ([sels (list car cadr)]) + (cond + [(null? sels) (loop (* N 2))] + [else + (let () + (define rtd (make-record-type + "r" + (let loop ([i N]) + (if (zero? i) + (list '[ptr y]) + (cons `[uptr ,(string->symbol (format "x~a" i))] + (loop (sub1 i))))))) + + (define (make-r) + (apply (record-constructor rtd) + (let loop ([i N]) + (if (zero? i) + '(the-y-value) + (cons 0 (loop (sub1 i))))))) + + (define r-y (record-accessor rtd N)) + (define set-r-y! (record-mutator rtd N)) + + (define rs (list (make-r) + (make-r) + (make-r))) + (collect (collect-maximum-generation)) + (set! rs (list (car rs) (caddr rs))) + (collect (collect-maximum-generation)) + (set-r-y! ((car sels) rs) (string-copy "new-string-to-go")) + (collect) + (and (equal? (r-y ((car sels) rs)) + "new-string-to-go") + (sel-loop (cdr sels))))])))) + ) diff --git a/mats/patch-compile-0-t-f-f b/mats/patch-compile-0-t-f-f index 5a096b0771..e0ca03f29e 100644 --- a/mats/patch-compile-0-t-f-f +++ b/mats/patch-compile-0-t-f-f @@ -1,5 +1,5 @@ -*** errors-compile-0-f-f-f 2020-03-11 22:32:59.000000000 -0600 ---- errors-compile-0-t-f-f 2020-03-11 22:04:54.000000000 -0600 +*** errors-compile-0-f-f-f 2020-04-20 14:03:37.000000000 -0600 +--- errors-compile-0-t-f-f 2020-04-20 14:17:38.000000000 -0600 *************** *** 222,228 **** 3.mo:Expected error in mat case-lambda: "incorrect number of arguments 2 to #". @@ -3861,7 +3861,7 @@ misc.mo:Expected error in mat compiler3: "incorrect argument count in call (consumer 1 2)". misc.mo:Expected error in mat compiler3: "variable goto is not bound". *************** -*** 4108,4114 **** +*** 4113,4119 **** misc.mo:Expected error in mat $fasl-file-equal?: "$fasl-file-equal?: failed for probably-does-not-exist: no such file or directory". misc.mo:Expected error in mat $fasl-file-equal?: "$fasl-file-equal?: failed for probably-does-not-exist: no such file or directory". misc.mo:Expected error in mat $fasl-file-equal?: "$fasl-file-equal?: record comparison failed while comparing testfile-fatfib1.so and testfile-fatfib3.so within fasl entry 4". @@ -3869,7 +3869,7 @@ misc.mo:Expected error in mat cost-center: "with-cost-center: foo is not a cost center". misc.mo:Expected error in mat cost-center: "with-cost-center: bar is not a procedure". misc.mo:Expected error in mat cost-center: "cost-center-instruction-count: 5 is not a cost center". ---- 4108,4114 ---- +--- 4113,4119 ---- misc.mo:Expected error in mat $fasl-file-equal?: "$fasl-file-equal?: failed for probably-does-not-exist: no such file or directory". misc.mo:Expected error in mat $fasl-file-equal?: "$fasl-file-equal?: failed for probably-does-not-exist: no such file or directory". misc.mo:Expected error in mat $fasl-file-equal?: "$fasl-file-equal?: record comparison failed while comparing testfile-fatfib1.so and testfile-fatfib3.so within fasl entry 4". @@ -3878,7 +3878,7 @@ misc.mo:Expected error in mat cost-center: "with-cost-center: bar is not a procedure". misc.mo:Expected error in mat cost-center: "cost-center-instruction-count: 5 is not a cost center". *************** -*** 4162,4169 **** +*** 4167,4174 **** misc.mo:Expected error in mat apropos: "apropos: 3 is not a symbol or string". misc.mo:Expected error in mat apropos: "apropos: (hit me) is not a symbol or string". misc.mo:Expected error in mat apropos: "apropos-list: b is not an environment". @@ -3887,7 +3887,7 @@ misc.mo:Expected error in mat apropos: "variable $apropos-unbound1 is not bound". misc.mo:Expected error in mat apropos: "variable $apropos-unbound2 is not bound". misc.mo:Expected error in mat simplify-if: "textual-port?: a is not a port". ---- 4162,4169 ---- +--- 4167,4174 ---- misc.mo:Expected error in mat apropos: "apropos: 3 is not a symbol or string". misc.mo:Expected error in mat apropos: "apropos: (hit me) is not a symbol or string". misc.mo:Expected error in mat apropos: "apropos-list: b is not an environment". @@ -3897,7 +3897,7 @@ misc.mo:Expected error in mat apropos: "variable $apropos-unbound2 is not bound". misc.mo:Expected error in mat simplify-if: "textual-port?: a is not a port". *************** -*** 4178,4193 **** +*** 4183,4198 **** misc.mo:Expected error in mat pariah: "invalid syntax (pariah)". misc.mo:Expected error in mat pariah: "invalid syntax (pariah . 17)". misc.mo:Expected error in mat procedure-arity-mask: "procedure-arity-mask: 17 is not a procedure". @@ -3914,7 +3914,7 @@ misc.mo:Expected error in mat wrapper-procedure: "make-arity-wrapper-procedure: 1 is not a procedure". misc.mo:Expected error in mat wrapper-procedure: "make-arity-wrapper-procedure: not-a-procedure is not a procedure". misc.mo:Expected error in mat wrapper-procedure: "make-arity-wrapper-procedure: not-an-exact-integer is not an arity mask". ---- 4178,4193 ---- +--- 4183,4198 ---- misc.mo:Expected error in mat pariah: "invalid syntax (pariah)". misc.mo:Expected error in mat pariah: "invalid syntax (pariah . 17)". misc.mo:Expected error in mat procedure-arity-mask: "procedure-arity-mask: 17 is not a procedure". @@ -3932,7 +3932,7 @@ misc.mo:Expected error in mat wrapper-procedure: "make-arity-wrapper-procedure: not-a-procedure is not a procedure". misc.mo:Expected error in mat wrapper-procedure: "make-arity-wrapper-procedure: not-an-exact-integer is not an arity mask". *************** -*** 4197,4209 **** +*** 4202,4233 **** misc.mo:Expected error in mat wrapper-procedure: "wrapper-procedure-data: 1 is not a wrapper procedure". misc.mo:Expected error in mat wrapper-procedure: "wrapper-procedure-data: # is not a wrapper procedure". misc.mo:Expected error in mat wrapper-procedure: "wrapper-procedure-data: # is not a wrapper procedure". @@ -3946,7 +3946,26 @@ misc.mo:Expected error in mat wrapper-procedure: "set-wrapper-procedure-data!: 1 is not a wrapper procedure". misc.mo:Expected error in mat wrapper-procedure: "set-wrapper-procedure-data!: # is not a wrapper procedure". misc.mo:Expected error in mat wrapper-procedure: "set-wrapper-procedure-data!: # is not a wrapper procedure". ---- 4197,4209 ---- + misc.mo:Expected error in mat phantom-bytevector: "make-phantom-bytevector: -1 is not a valid phantom bytevector length". + misc.mo:Expected error in mat phantom-bytevector: "make-phantom-bytevector: 1267650600228229401496703205376 is not a valid phantom bytevector length". + misc.mo:Expected error in mat phantom-bytevector: "make-phantom-bytevector: x is not a valid phantom bytevector length". +! misc.mo:Expected error in mat immobile: "incorrect argument count in call (box-immobile)". +! misc.mo:Expected error in mat immobile: "incorrect argument count in call (box-immobile 1 2)". +! misc.mo:Expected error in mat immobile: "incorrect argument count in call (make-immobile-vector)". + misc.mo:Expected error in mat immobile: "make-immobile-vector: a is not a valid vector length". + misc.mo:Expected error in mat immobile: "make-immobile-vector: -10 is not a valid vector length". + misc.mo:Expected error in mat immobile: "make-immobile-vector: 1267650600228229401496703205376 is not a valid vector length". +! misc.mo:Expected error in mat immobile: "incorrect argument count in call (make-immobile-vector 10 1 2)". +! misc.mo:Expected error in mat immobile: "incorrect argument count in call (make-immobile-bytevector)". + misc.mo:Expected error in mat immobile: "make-immobile-bytevector: a is not a valid bytevector length". + misc.mo:Expected error in mat immobile: "variable make-immobile-byte-vector is not bound". + misc.mo:Expected error in mat immobile: "make-immobile-bytevector: 1267650600228229401496703205376 is not a valid bytevector length". + misc.mo:Expected error in mat immobile: "make-immobile-bytevector: 1024 is not a valid fill value". +! misc.mo:Expected error in mat immobile: "incorrect argument count in call (make-immobile-bytevector 10 1 2)". + cp0.mo:Expected error in mat cp0-regression: "attempt to reference undefined variable x". + cp0.mo:Expected error in mat cp0-regression: "incorrect argument count in call (g)". + cp0.mo:Expected error in mat cp0-regression: "incorrect argument count in call (cont0 (quote x))". +--- 4202,4233 ---- misc.mo:Expected error in mat wrapper-procedure: "wrapper-procedure-data: 1 is not a wrapper procedure". misc.mo:Expected error in mat wrapper-procedure: "wrapper-procedure-data: # is not a wrapper procedure". misc.mo:Expected error in mat wrapper-procedure: "wrapper-procedure-data: # is not a wrapper procedure". @@ -3960,8 +3979,27 @@ misc.mo:Expected error in mat wrapper-procedure: "set-wrapper-procedure-data!: 1 is not a wrapper procedure". misc.mo:Expected error in mat wrapper-procedure: "set-wrapper-procedure-data!: # is not a wrapper procedure". misc.mo:Expected error in mat wrapper-procedure: "set-wrapper-procedure-data!: # is not a wrapper procedure". + misc.mo:Expected error in mat phantom-bytevector: "make-phantom-bytevector: -1 is not a valid phantom bytevector length". + misc.mo:Expected error in mat phantom-bytevector: "make-phantom-bytevector: 1267650600228229401496703205376 is not a valid phantom bytevector length". + misc.mo:Expected error in mat phantom-bytevector: "make-phantom-bytevector: x is not a valid phantom bytevector length". +! misc.mo:Expected error in mat immobile: "incorrect number of arguments 0 to #". +! misc.mo:Expected error in mat immobile: "incorrect number of arguments 2 to #". +! misc.mo:Expected error in mat immobile: "incorrect number of arguments 0 to #". + misc.mo:Expected error in mat immobile: "make-immobile-vector: a is not a valid vector length". + misc.mo:Expected error in mat immobile: "make-immobile-vector: -10 is not a valid vector length". + misc.mo:Expected error in mat immobile: "make-immobile-vector: 1267650600228229401496703205376 is not a valid vector length". +! misc.mo:Expected error in mat immobile: "incorrect number of arguments 3 to #". +! misc.mo:Expected error in mat immobile: "incorrect number of arguments 0 to #". + misc.mo:Expected error in mat immobile: "make-immobile-bytevector: a is not a valid bytevector length". + misc.mo:Expected error in mat immobile: "variable make-immobile-byte-vector is not bound". + misc.mo:Expected error in mat immobile: "make-immobile-bytevector: 1267650600228229401496703205376 is not a valid bytevector length". + misc.mo:Expected error in mat immobile: "make-immobile-bytevector: 1024 is not a valid fill value". +! misc.mo:Expected error in mat immobile: "incorrect number of arguments 3 to #". + cp0.mo:Expected error in mat cp0-regression: "attempt to reference undefined variable x". + cp0.mo:Expected error in mat cp0-regression: "incorrect argument count in call (g)". + cp0.mo:Expected error in mat cp0-regression: "incorrect argument count in call (cont0 (quote x))". *************** -*** 4223,4231 **** +*** 4241,4249 **** cp0.mo:Expected error in mat cp0-regression: "condition: #f is not a condition". cp0.mo:Expected error in mat cp0-regression: "apply: 0 is not a proper list". cp0.mo:Expected error in mat cp0-regression: "apply: 2 is not a proper list". @@ -3971,7 +4009,7 @@ cp0.mo:Expected error in mat expand-output: "expand-output: #t is not a textual output port or #f". cp0.mo:Expected error in mat expand-output: "expand-output: # is not a textual output port or #f". cp0.mo:Expected error in mat expand/optimize-output: "expand/optimize-output: #t is not a textual output port or #f". ---- 4223,4231 ---- +--- 4241,4249 ---- cp0.mo:Expected error in mat cp0-regression: "condition: #f is not a condition". cp0.mo:Expected error in mat cp0-regression: "apply: 0 is not a proper list". cp0.mo:Expected error in mat cp0-regression: "apply: 2 is not a proper list". @@ -3982,7 +4020,7 @@ cp0.mo:Expected error in mat expand-output: "expand-output: # is not a textual output port or #f". cp0.mo:Expected error in mat expand/optimize-output: "expand/optimize-output: #t is not a textual output port or #f". *************** -*** 4289,4297 **** +*** 4307,4315 **** 5_6.mo:Expected error in mat list->fxvector: "list->fxvector: (1 2 . 3) is not a proper list". 5_6.mo:Expected error in mat list->fxvector: "list->fxvector: (1 2 3 2 3 2 ...) is circular". 5_6.mo:Expected error in mat fxvector->list: "fxvector->list: (a b c) is not an fxvector". @@ -3992,7 +4030,7 @@ 5_6.mo:Expected error in mat vector-map: "vector-map: #() is not a procedure". 5_6.mo:Expected error in mat vector-map: "vector-map: #() is not a procedure". 5_6.mo:Expected error in mat vector-map: "vector-map: #() is not a procedure". ---- 4289,4297 ---- +--- 4307,4315 ---- 5_6.mo:Expected error in mat list->fxvector: "list->fxvector: (1 2 . 3) is not a proper list". 5_6.mo:Expected error in mat list->fxvector: "list->fxvector: (1 2 3 2 3 2 ...) is circular". 5_6.mo:Expected error in mat fxvector->list: "fxvector->list: (a b c) is not an fxvector". @@ -4003,7 +4041,7 @@ 5_6.mo:Expected error in mat vector-map: "vector-map: #() is not a procedure". 5_6.mo:Expected error in mat vector-map: "vector-map: #() is not a procedure". *************** -*** 4306,4314 **** +*** 4324,4332 **** 5_6.mo:Expected error in mat vector-map: "vector-map: lengths of input vectors #() and #(x) differ". 5_6.mo:Expected error in mat vector-map: "vector-map: lengths of input vectors #(y) and #() differ". 5_6.mo:Expected error in mat vector-map: "vector-map: lengths of input vectors #(y) and #() differ". @@ -4013,7 +4051,7 @@ 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: #() is not a procedure". 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: #() is not a procedure". 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: #() is not a procedure". ---- 4306,4314 ---- +--- 4324,4332 ---- 5_6.mo:Expected error in mat vector-map: "vector-map: lengths of input vectors #() and #(x) differ". 5_6.mo:Expected error in mat vector-map: "vector-map: lengths of input vectors #(y) and #() differ". 5_6.mo:Expected error in mat vector-map: "vector-map: lengths of input vectors #(y) and #() differ". @@ -4024,7 +4062,7 @@ 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: #() is not a procedure". 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: #() is not a procedure". *************** -*** 4323,4340 **** +*** 4341,4358 **** 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: lengths of input vectors #() and #(x) differ". 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: lengths of input vectors #(y) and #() differ". 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: lengths of input vectors #(y) and #() differ". @@ -4043,7 +4081,7 @@ 5_6.mo:Expected error in mat vector-sort!: "vector-sort!: 3 is not a mutable vector". 5_6.mo:Expected error in mat vector-sort!: "vector-sort!: (1 2 3) is not a mutable vector". 5_6.mo:Expected error in mat vector-sort!: "vector-sort!: #(a b c) is not a procedure". ---- 4323,4340 ---- +--- 4341,4358 ---- 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: lengths of input vectors #() and #(x) differ". 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: lengths of input vectors #(y) and #() differ". 5_6.mo:Expected error in mat vector-for-each: "vector-for-each: lengths of input vectors #(y) and #() differ". @@ -4063,7 +4101,7 @@ 5_6.mo:Expected error in mat vector-sort!: "vector-sort!: (1 2 3) is not a mutable vector". 5_6.mo:Expected error in mat vector-sort!: "vector-sort!: #(a b c) is not a procedure". *************** -*** 4345,4353 **** +*** 4363,4371 **** 5_6.mo:Expected error in mat vector->immutable-vector: "vector-sort!: #(1 2 3) is not a mutable vector". 5_6.mo:Expected error in mat fxvector->immutable-fxvector: "fxvector-set!: #vfx(1 2 3) is not a mutable fxvector". 5_6.mo:Expected error in mat fxvector->immutable-fxvector: "fxvector-fill!: #vfx(1 2 3) is not a mutable fxvector". @@ -4073,7 +4111,7 @@ 5_6.mo:Expected error in mat vector-cas!: "vector-cas!: 1 is not a mutable vector". 5_6.mo:Expected error in mat vector-cas!: "vector-cas!: #(4 5 3) is not a mutable vector". 5_6.mo:Expected error in mat vector-cas!: "vector-cas!: #(4 5 3) is not a valid index for #(4 5 3)". ---- 4345,4353 ---- +--- 4363,4371 ---- 5_6.mo:Expected error in mat vector->immutable-vector: "vector-sort!: #(1 2 3) is not a mutable vector". 5_6.mo:Expected error in mat fxvector->immutable-fxvector: "fxvector-set!: #vfx(1 2 3) is not a mutable fxvector". 5_6.mo:Expected error in mat fxvector->immutable-fxvector: "fxvector-fill!: #vfx(1 2 3) is not a mutable fxvector". @@ -4084,7 +4122,7 @@ 5_6.mo:Expected error in mat vector-cas!: "vector-cas!: #(4 5 3) is not a mutable vector". 5_6.mo:Expected error in mat vector-cas!: "vector-cas!: #(4 5 3) is not a valid index for #(4 5 3)". *************** -*** 4404,4411 **** +*** 4422,4429 **** 5_7.mo:Expected error in mat putprop-getprop: "getprop: 3 is not a symbol". 5_7.mo:Expected error in mat putprop-getprop: "putprop: "hi" is not a symbol". 5_7.mo:Expected error in mat putprop-getprop: "property-list: (a b c) is not a symbol". @@ -4093,7 +4131,7 @@ 5_8.mo:Expected error in mat box-cas!: "box-cas!: 1 is not a mutable box". 5_8.mo:Expected error in mat box-cas!: "box-cas!: #&1 is not a mutable box". 6.mo:Expected error in mat port-operations: "open-input-file: failed for nonexistent file: no such file or directory". ---- 4404,4411 ---- +--- 4422,4429 ---- 5_7.mo:Expected error in mat putprop-getprop: "getprop: 3 is not a symbol". 5_7.mo:Expected error in mat putprop-getprop: "putprop: "hi" is not a symbol". 5_7.mo:Expected error in mat putprop-getprop: "property-list: (a b c) is not a symbol". @@ -4103,7 +4141,7 @@ 5_8.mo:Expected error in mat box-cas!: "box-cas!: #&1 is not a mutable box". 6.mo:Expected error in mat port-operations: "open-input-file: failed for nonexistent file: no such file or directory". *************** -*** 4443,4464 **** +*** 4461,4482 **** 6.mo:Expected error in mat port-operations: "clear-output-port: not permitted on closed port #". 6.mo:Expected error in mat port-operations: "current-output-port: a is not a textual output port". 6.mo:Expected error in mat port-operations: "current-input-port: a is not a textual input port". @@ -4126,7 +4164,7 @@ 6.mo:Expected error in mat port-operations1: "open-input-output-file: furball is not a string". 6.mo:Expected error in mat port-operations1: "open-input-output-file: failed for /probably/not/a/good/path: no such file or directory". 6.mo:Expected error in mat port-operations1: "open-input-output-file: invalid option compressed". ---- 4443,4464 ---- +--- 4461,4482 ---- 6.mo:Expected error in mat port-operations: "clear-output-port: not permitted on closed port #". 6.mo:Expected error in mat port-operations: "current-output-port: a is not a textual output port". 6.mo:Expected error in mat port-operations: "current-input-port: a is not a textual input port". @@ -4150,7 +4188,7 @@ 6.mo:Expected error in mat port-operations1: "open-input-output-file: failed for /probably/not/a/good/path: no such file or directory". 6.mo:Expected error in mat port-operations1: "open-input-output-file: invalid option compressed". *************** -*** 4467,4473 **** +*** 4485,4491 **** 6.mo:Expected error in mat port-operations1: "truncate-file: all-the-way is not a valid length". 6.mo:Expected error in mat port-operations1: "truncate-file: # is not an output port". 6.mo:Expected error in mat port-operations1: "truncate-file: animal-crackers is not an output port". @@ -4158,7 +4196,7 @@ 6.mo:Expected error in mat port-operations1: "truncate-file: not permitted on closed port #". 6.mo:Expected error in mat port-operations1: "get-output-string: # is not a string output port". 6.mo:Expected error in mat port-operations1: "get-output-string: # is not a string output port". ---- 4467,4473 ---- +--- 4485,4491 ---- 6.mo:Expected error in mat port-operations1: "truncate-file: all-the-way is not a valid length". 6.mo:Expected error in mat port-operations1: "truncate-file: # is not an output port". 6.mo:Expected error in mat port-operations1: "truncate-file: animal-crackers is not an output port". @@ -4167,7 +4205,7 @@ 6.mo:Expected error in mat port-operations1: "get-output-string: # is not a string output port". 6.mo:Expected error in mat port-operations1: "get-output-string: # is not a string output port". *************** -*** 4484,4491 **** +*** 4502,4509 **** 6.mo:Expected error in mat string-port-file-position: "file-position: -1 is not a valid position". 6.mo:Expected error in mat fresh-line: "fresh-line: 3 is not a textual output port". 6.mo:Expected error in mat fresh-line: "fresh-line: # is not a textual output port". @@ -4176,7 +4214,7 @@ 6.mo:Expected error in mat pretty-print: "pretty-format: 3 is not a symbol". 6.mo:Expected error in mat pretty-print: "pretty-format: invalid format (bad 0 ... ... 0 format)". 6.mo:Expected warning in mat cp1in-verify-format-warnings: "compile: too few arguments for control string "~a~~~s" in call to format". ---- 4484,4491 ---- +--- 4502,4509 ---- 6.mo:Expected error in mat string-port-file-position: "file-position: -1 is not a valid position". 6.mo:Expected error in mat fresh-line: "fresh-line: 3 is not a textual output port". 6.mo:Expected error in mat fresh-line: "fresh-line: # is not a textual output port". @@ -4186,7 +4224,7 @@ 6.mo:Expected error in mat pretty-print: "pretty-format: invalid format (bad 0 ... ... 0 format)". 6.mo:Expected warning in mat cp1in-verify-format-warnings: "compile: too few arguments for control string "~a~~~s" in call to format". *************** -*** 6969,7000 **** +*** 6987,7018 **** io.mo:Expected error in mat port-operations: "put-u8: not permitted on closed port #". io.mo:Expected error in mat port-operations: "put-bytevector: not permitted on closed port #". io.mo:Expected error in mat port-operations: "flush-output-port: not permitted on closed port #". @@ -4219,7 +4257,7 @@ io.mo:Expected error in mat port-operations1: "open-file-input/output-port: failed for /probably/not/a/good/path: no such file or directory". io.mo:Expected error in mat port-operations1: "invalid file option uncompressed". io.mo:Expected error in mat port-operations1: "invalid file option truncate". ---- 6969,7000 ---- +--- 6987,7018 ---- io.mo:Expected error in mat port-operations: "put-u8: not permitted on closed port #". io.mo:Expected error in mat port-operations: "put-bytevector: not permitted on closed port #". io.mo:Expected error in mat port-operations: "flush-output-port: not permitted on closed port #". @@ -4253,7 +4291,7 @@ io.mo:Expected error in mat port-operations1: "invalid file option uncompressed". io.mo:Expected error in mat port-operations1: "invalid file option truncate". *************** -*** 7005,7011 **** +*** 7023,7029 **** io.mo:Expected error in mat port-operations1: "set-port-length!: all-the-way is not a valid length". io.mo:Expected error in mat port-operations1: "truncate-port: # is not an output port". io.mo:Expected error in mat port-operations1: "truncate-port: animal-crackers is not an output port". @@ -4261,7 +4299,7 @@ io.mo:Expected error in mat port-operations1: "truncate-port: not permitted on closed port #". io.mo:Expected error in mat port-operations3: "file-port?: "not a port" is not a port". io.mo:Expected error in mat port-operations3: "port-file-descriptor: oops is not a port". ---- 7005,7011 ---- +--- 7023,7029 ---- io.mo:Expected error in mat port-operations1: "set-port-length!: all-the-way is not a valid length". io.mo:Expected error in mat port-operations1: "truncate-port: # is not an output port". io.mo:Expected error in mat port-operations1: "truncate-port: animal-crackers is not an output port". @@ -4270,7 +4308,7 @@ io.mo:Expected error in mat port-operations3: "file-port?: "not a port" is not a port". io.mo:Expected error in mat port-operations3: "port-file-descriptor: oops is not a port". *************** -*** 7188,7200 **** +*** 7206,7218 **** io.mo:Expected error in mat low-level-port-operations: "set-binary-port-output-size!: #vu8(1 2 3) is not a valid size for #". io.mo:Expected error in mat low-level-port-operations: "set-binary-port-output-size!: -1 is not a valid size for #". io.mo:Expected error in mat low-level-port-operations: "set-binary-port-output-size!: 6 is not a valid size for #". @@ -4284,7 +4322,7 @@ io.mo:Expected error in mat custom-port-buffer-size: "custom-port-buffer-size: shoe is not a positive fixnum". io.mo:Expected error in mat custom-port-buffer-size: "custom-port-buffer-size: 0 is not a positive fixnum". io.mo:Expected error in mat custom-port-buffer-size: "custom-port-buffer-size: -15 is not a positive fixnum". ---- 7188,7200 ---- +--- 7206,7218 ---- io.mo:Expected error in mat low-level-port-operations: "set-binary-port-output-size!: #vu8(1 2 3) is not a valid size for #". io.mo:Expected error in mat low-level-port-operations: "set-binary-port-output-size!: -1 is not a valid size for #". io.mo:Expected error in mat low-level-port-operations: "set-binary-port-output-size!: 6 is not a valid size for #". @@ -4299,7 +4337,7 @@ io.mo:Expected error in mat custom-port-buffer-size: "custom-port-buffer-size: 0 is not a positive fixnum". io.mo:Expected error in mat custom-port-buffer-size: "custom-port-buffer-size: -15 is not a positive fixnum". *************** -*** 7220,7235 **** +*** 7238,7253 **** io.mo:Expected error in mat compression: "port-file-compressed!: cannot compress input/output port #". io.mo:Expected error in mat compression: "port-file-compressed!: # is not a file port". io.mo:Expected error in mat compression: "port-file-compressed!: cannot compress input/output port #". @@ -4316,7 +4354,7 @@ io.mo:Expected error in mat custom-binary-ports: "unget-u8: cannot unget 255 on #". io.mo:Expected error in mat custom-binary-ports: "put-u8: # is not a binary output port". io.mo:Expected error in mat custom-binary-ports: "port-length: # does not support operation". ---- 7220,7235 ---- +--- 7238,7253 ---- io.mo:Expected error in mat compression: "port-file-compressed!: cannot compress input/output port #". io.mo:Expected error in mat compression: "port-file-compressed!: # is not a file port". io.mo:Expected error in mat compression: "port-file-compressed!: cannot compress input/output port #". @@ -4334,7 +4372,7 @@ io.mo:Expected error in mat custom-binary-ports: "put-u8: # is not a binary output port". io.mo:Expected error in mat custom-binary-ports: "port-length: # does not support operation". *************** -*** 7301,7316 **** +*** 7319,7334 **** io.mo:Expected error in mat current-ports: "console-output-port: # is not a textual output port". io.mo:Expected error in mat current-ports: "console-error-port: # is not a textual output port". io.mo:Expected error in mat current-transcoder: "current-transcoder: # is not a transcoder". @@ -4351,7 +4389,7 @@ io.mo:Expected error in mat utf-16-codec: "utf-16-codec: invalid endianness #f". io.mo:Expected error in mat to-fold-or-not-to-fold: "get-datum: invalid character name #\newLine at char 0 of #". io.mo:Expected error in mat to-fold-or-not-to-fold: "get-datum: invalid character name #\newLine at char 15 of #". ---- 7301,7316 ---- +--- 7319,7334 ---- io.mo:Expected error in mat current-ports: "console-output-port: # is not a textual output port". io.mo:Expected error in mat current-ports: "console-error-port: # is not a textual output port". io.mo:Expected error in mat current-transcoder: "current-transcoder: # is not a transcoder". @@ -4369,7 +4407,7 @@ io.mo:Expected error in mat to-fold-or-not-to-fold: "get-datum: invalid character name #\newLine at char 0 of #". io.mo:Expected error in mat to-fold-or-not-to-fold: "get-datum: invalid character name #\newLine at char 15 of #". *************** -*** 7482,7488 **** +*** 7500,7506 **** 7.mo:Expected error in mat eval-when: "invalid syntax visit-x". 7.mo:Expected error in mat eval-when: "invalid syntax revisit-x". 7.mo:Expected error in mat compile-whole-program: "compile-whole-program: failed for nosuchfile.wpo: no such file or directory". @@ -4377,7 +4415,7 @@ 7.mo:Expected error in mat compile-whole-program: "separate-eval: Exception in environment: attempt to import invisible library (testfile-wpo-lib) 7.mo:Expected error in mat compile-whole-program: "separate-eval: Exception: library (testfile-wpo-a4) not found 7.mo:Expected error in mat compile-whole-program: "separate-eval: Exception: library (testfile-wpo-c4) not found ---- 7482,7488 ---- +--- 7500,7506 ---- 7.mo:Expected error in mat eval-when: "invalid syntax visit-x". 7.mo:Expected error in mat eval-when: "invalid syntax revisit-x". 7.mo:Expected error in mat compile-whole-program: "compile-whole-program: failed for nosuchfile.wpo: no such file or directory". @@ -4386,7 +4424,7 @@ 7.mo:Expected error in mat compile-whole-program: "separate-eval: Exception: library (testfile-wpo-a4) not found 7.mo:Expected error in mat compile-whole-program: "separate-eval: Exception: library (testfile-wpo-c4) not found *************** -*** 7548,7574 **** +*** 7566,7592 **** 7.mo:Expected error in mat concatenate-object-files: "separate-eval: Exception in verify-loadability: cannot find object file for library (testfile-cof1A) 7.mo:Expected error in mat concatenate-object-files: "separate-eval: Exception in verify-loadability: cannot find object file for library (testfile-cof1B) 7.mo:Expected error in mat top-level-value-functions: "top-level-bound?: "hello" is not a symbol". @@ -4414,7 +4452,7 @@ 7.mo:Expected error in mat top-level-value-functions: "define-top-level-value: hello is not an environment". 7.mo:Expected error in mat top-level-value-functions: "define-top-level-value: # is not a symbol". 7.mo:Expected error in mat top-level-value-functions: "variable i-am-not-bound-i-hope is not bound". ---- 7548,7574 ---- +--- 7566,7592 ---- 7.mo:Expected error in mat concatenate-object-files: "separate-eval: Exception in verify-loadability: cannot find object file for library (testfile-cof1A) 7.mo:Expected error in mat concatenate-object-files: "separate-eval: Exception in verify-loadability: cannot find object file for library (testfile-cof1B) 7.mo:Expected error in mat top-level-value-functions: "top-level-bound?: "hello" is not a symbol". @@ -4443,7 +4481,7 @@ 7.mo:Expected error in mat top-level-value-functions: "define-top-level-value: # is not a symbol". 7.mo:Expected error in mat top-level-value-functions: "variable i-am-not-bound-i-hope is not bound". *************** -*** 7883,7889 **** +*** 7901,7907 **** record.mo:Expected error in mat r6rs-records-procedural: "incorrect number of arguments 1 to #". record.mo:Expected error in mat r6rs-records-procedural: "incorrect number of arguments 1 to #". record.mo:Expected error in mat r6rs-records-procedural: "incorrect number of arguments 3 to #". @@ -4451,7 +4489,7 @@ record.mo:Expected error in mat r6rs-records-procedural: "incorrect number of arguments 4 to #". record.mo:Expected error in mat r6rs-records-procedural: "make-record-constructor-descriptor: record constructor descriptor # is not for parent of record type #". record.mo:Expected error in mat r6rs-records-procedural: "make-record-type-descriptor: cannot extend sealed record type #". ---- 7883,7889 ---- +--- 7901,7907 ---- record.mo:Expected error in mat r6rs-records-procedural: "incorrect number of arguments 1 to #". record.mo:Expected error in mat r6rs-records-procedural: "incorrect number of arguments 1 to #". record.mo:Expected error in mat r6rs-records-procedural: "incorrect number of arguments 3 to #". @@ -4460,7 +4498,7 @@ record.mo:Expected error in mat r6rs-records-procedural: "make-record-constructor-descriptor: record constructor descriptor # is not for parent of record type #". record.mo:Expected error in mat r6rs-records-procedural: "make-record-type-descriptor: cannot extend sealed record type #". *************** -*** 7973,8087 **** +*** 7991,8105 **** hash.mo:Expected error in mat old-hash-table: "hash-table-for-each: ((a . b)) is not an eq hashtable". hash.mo:Expected error in mat old-hash-table: "incorrect number of arguments 2 to #". hash.mo:Expected error in mat old-hash-table: "incorrect number of arguments 2 to #". @@ -4576,7 +4614,7 @@ hash.mo:Expected error in mat hashtable-arguments: "hashtable-ephemeron?: (hash . table) is not a hashtable". hash.mo:Expected error in mat hash-return-value: "hashtable-ref: invalid hash-function # return value "oops" for any". hash.mo:Expected error in mat hash-return-value: "hashtable-ref: invalid hash-function # return value 3.5 for any". ---- 7973,8087 ---- +--- 7991,8105 ---- hash.mo:Expected error in mat old-hash-table: "hash-table-for-each: ((a . b)) is not an eq hashtable". hash.mo:Expected error in mat old-hash-table: "incorrect number of arguments 2 to #". hash.mo:Expected error in mat old-hash-table: "incorrect number of arguments 2 to #". @@ -4693,7 +4731,7 @@ hash.mo:Expected error in mat hash-return-value: "hashtable-ref: invalid hash-function # return value "oops" for any". hash.mo:Expected error in mat hash-return-value: "hashtable-ref: invalid hash-function # return value 3.5 for any". *************** -*** 8104,8226 **** +*** 8122,8244 **** hash.mo:Expected error in mat hash-return-value: "hashtable-delete!: invalid hash-function # return value "oops" for any". hash.mo:Expected error in mat hash-return-value: "hashtable-delete!: invalid hash-function # return value 3.5 for any". hash.mo:Expected error in mat hash-return-value: "hashtable-delete!: invalid hash-function # return value 1+2i for any". @@ -4817,7 +4855,7 @@ hash.mo:Expected error in mat eqv-hashtable-arguments: "make-ephemeron-eqv-hashtable: invalid size argument -1". hash.mo:Expected error in mat eqv-hashtable-arguments: "make-ephemeron-eqv-hashtable: invalid size argument #t". hash.mo:Expected error in mat eqv-hashtable-arguments: "make-ephemeron-eqv-hashtable: invalid size argument #f". ---- 8104,8226 ---- +--- 8122,8244 ---- hash.mo:Expected error in mat hash-return-value: "hashtable-delete!: invalid hash-function # return value "oops" for any". hash.mo:Expected error in mat hash-return-value: "hashtable-delete!: invalid hash-function # return value 3.5 for any". hash.mo:Expected error in mat hash-return-value: "hashtable-delete!: invalid hash-function # return value 1+2i for any". @@ -4942,7 +4980,7 @@ hash.mo:Expected error in mat eqv-hashtable-arguments: "make-ephemeron-eqv-hashtable: invalid size argument #t". hash.mo:Expected error in mat eqv-hashtable-arguments: "make-ephemeron-eqv-hashtable: invalid size argument #f". *************** -*** 8228,8243 **** +*** 8246,8261 **** hash.mo:Expected error in mat generic-hashtable: "hashtable-delete!: # is not mutable". hash.mo:Expected error in mat generic-hashtable: "hashtable-update!: # is not mutable". hash.mo:Expected error in mat generic-hashtable: "hashtable-update!: # is not mutable". @@ -4959,7 +4997,7 @@ hash.mo:Expected error in mat hash-functions: "string-ci-hash: hello is not a string". hash.mo:Expected error in mat fasl-other-hashtable: "fasl-write: invalid fasl object #". hash.mo:Expected error in mat fasl-other-hashtable: "fasl-write: invalid fasl object #". ---- 8228,8243 ---- +--- 8246,8261 ---- hash.mo:Expected error in mat generic-hashtable: "hashtable-delete!: # is not mutable". hash.mo:Expected error in mat generic-hashtable: "hashtable-update!: # is not mutable". hash.mo:Expected error in mat generic-hashtable: "hashtable-update!: # is not mutable". @@ -4977,7 +5015,7 @@ hash.mo:Expected error in mat fasl-other-hashtable: "fasl-write: invalid fasl object #". hash.mo:Expected error in mat fasl-other-hashtable: "fasl-write: invalid fasl object #". *************** -*** 8353,8360 **** +*** 8371,8378 **** 8.mo:Expected error in mat with-syntax: "invalid syntax a". 8.mo:Expected error in mat with-syntax: "duplicate pattern variable x in (x x)". 8.mo:Expected error in mat with-syntax: "duplicate pattern variable x in (x x)". @@ -4986,7 +5024,7 @@ 8.mo:Expected error in mat generate-temporaries: "generate-temporaries: improper list structure (a b . c)". 8.mo:Expected error in mat generate-temporaries: "generate-temporaries: cyclic list structure (a b c b c b ...)". 8.mo:Expected error in mat syntax->list: "syntax->list: invalid argument #". ---- 8353,8360 ---- +--- 8371,8378 ---- 8.mo:Expected error in mat with-syntax: "invalid syntax a". 8.mo:Expected error in mat with-syntax: "duplicate pattern variable x in (x x)". 8.mo:Expected error in mat with-syntax: "duplicate pattern variable x in (x x)". @@ -4996,7 +5034,7 @@ 8.mo:Expected error in mat generate-temporaries: "generate-temporaries: cyclic list structure (a b c b c b ...)". 8.mo:Expected error in mat syntax->list: "syntax->list: invalid argument #". *************** -*** 8971,8986 **** +*** 8989,9004 **** 8.mo:Expected error in mat rnrs-eval: "attempt to assign unbound identifier foo". 8.mo:Expected error in mat rnrs-eval: "invalid definition in immutable environment (define cons (quote #))". 8.mo:Expected error in mat top-level-syntax-functions: "top-level-syntax: "hello" is not a symbol". @@ -5013,7 +5051,7 @@ 8.mo:Expected error in mat top-level-syntax-functions: "define-top-level-syntax: hello is not an environment". 8.mo:Expected error in mat top-level-syntax-functions: "define-top-level-syntax: # is not a symbol". 8.mo:Expected error in mat top-level-syntax-functions: "define-top-level-syntax: cannot modify immutable environment #". ---- 8971,8986 ---- +--- 8989,9004 ---- 8.mo:Expected error in mat rnrs-eval: "attempt to assign unbound identifier foo". 8.mo:Expected error in mat rnrs-eval: "invalid definition in immutable environment (define cons (quote #))". 8.mo:Expected error in mat top-level-syntax-functions: "top-level-syntax: "hello" is not a symbol". @@ -5031,7 +5069,7 @@ 8.mo:Expected error in mat top-level-syntax-functions: "define-top-level-syntax: # is not a symbol". 8.mo:Expected error in mat top-level-syntax-functions: "define-top-level-syntax: cannot modify immutable environment #". *************** -*** 9079,9101 **** +*** 9097,9119 **** fx.mo:Expected error in mat fx=?: "fx=?: (a) is not a fixnum". fx.mo:Expected error in mat fx=?: "fx=?: is not a fixnum". fx.mo:Expected error in mat fx=?: "fx=?: <-int> is not a fixnum". @@ -5055,7 +5093,7 @@ fx.mo:Expected error in mat $fxu<: "incorrect number of arguments 1 to #". fx.mo:Expected error in mat $fxu<: "incorrect number of arguments 3 to #". fx.mo:Expected error in mat $fxu<: "$fxu<: <-int> is not a fixnum". ---- 9079,9101 ---- +--- 9097,9119 ---- fx.mo:Expected error in mat fx=?: "fx=?: (a) is not a fixnum". fx.mo:Expected error in mat fx=?: "fx=?: is not a fixnum". fx.mo:Expected error in mat fx=?: "fx=?: <-int> is not a fixnum". @@ -5080,7 +5118,7 @@ fx.mo:Expected error in mat $fxu<: "incorrect number of arguments 3 to #". fx.mo:Expected error in mat $fxu<: "$fxu<: <-int> is not a fixnum". *************** -*** 9127,9139 **** +*** 9145,9157 **** fx.mo:Expected error in mat r6rs:fx-: "fx-: #f is not a fixnum". fx.mo:Expected error in mat r6rs:fx-: "fx-: #f is not a fixnum". fx.mo:Expected error in mat fx*: "fx*: (a . b) is not a fixnum". @@ -5094,7 +5132,7 @@ fx.mo:Expected error in mat r6rs:fx*: "fx*: is not a fixnum". fx.mo:Expected error in mat r6rs:fx*: "fx*: <-int> is not a fixnum". fx.mo:Expected error in mat r6rs:fx*: "fx*: #f is not a fixnum". ---- 9127,9139 ---- +--- 9145,9157 ---- fx.mo:Expected error in mat r6rs:fx-: "fx-: #f is not a fixnum". fx.mo:Expected error in mat r6rs:fx-: "fx-: #f is not a fixnum". fx.mo:Expected error in mat fx*: "fx*: (a . b) is not a fixnum". @@ -5109,7 +5147,7 @@ fx.mo:Expected error in mat r6rs:fx*: "fx*: <-int> is not a fixnum". fx.mo:Expected error in mat r6rs:fx*: "fx*: #f is not a fixnum". *************** -*** 9183,9195 **** +*** 9201,9213 **** fx.mo:Expected error in mat fx1+: "fx1+: <-int> is not a fixnum". fx.mo:Expected error in mat fx1+: "fx1+: is not a fixnum". fx.mo:Expected error in mat fx1+: "fx1+: a is not a fixnum". @@ -5123,7 +5161,7 @@ fx.mo:Expected error in mat fxmax: "fxmax: a is not a fixnum". fx.mo:Expected error in mat fxmax: "fxmax: is not a fixnum". fx.mo:Expected error in mat fxmax: "fxmax: <-int> is not a fixnum". ---- 9183,9195 ---- +--- 9201,9213 ---- fx.mo:Expected error in mat fx1+: "fx1+: <-int> is not a fixnum". fx.mo:Expected error in mat fx1+: "fx1+: is not a fixnum". fx.mo:Expected error in mat fx1+: "fx1+: a is not a fixnum". @@ -5138,7 +5176,7 @@ fx.mo:Expected error in mat fxmax: "fxmax: is not a fixnum". fx.mo:Expected error in mat fxmax: "fxmax: <-int> is not a fixnum". *************** -*** 9287,9296 **** +*** 9305,9314 **** fx.mo:Expected error in mat fxarithmetic-shift: "fxarithmetic-shift: fixnum overflow with arguments and 10". fx.mo:Expected error in mat fxarithmetic-shift: "fxarithmetic-shift: fixnum overflow with arguments -4097 and ". fx.mo:Expected error in mat fxarithmetic-shift: "fxarithmetic-shift: fixnum overflow with arguments <-int> and 1". @@ -5149,7 +5187,7 @@ fx.mo:Expected error in mat fxbit-field: "fxbit-field: 35.0 is not a fixnum". fx.mo:Expected error in mat fxbit-field: "fxbit-field: 5.0 is not a valid start index". fx.mo:Expected error in mat fxbit-field: "fxbit-field: 8.0 is not a valid end index". ---- 9287,9296 ---- +--- 9305,9314 ---- fx.mo:Expected error in mat fxarithmetic-shift: "fxarithmetic-shift: fixnum overflow with arguments and 10". fx.mo:Expected error in mat fxarithmetic-shift: "fxarithmetic-shift: fixnum overflow with arguments -4097 and ". fx.mo:Expected error in mat fxarithmetic-shift: "fxarithmetic-shift: fixnum overflow with arguments <-int> and 1". @@ -5161,7 +5199,7 @@ fx.mo:Expected error in mat fxbit-field: "fxbit-field: 5.0 is not a valid start index". fx.mo:Expected error in mat fxbit-field: "fxbit-field: 8.0 is not a valid end index". *************** -*** 9304,9337 **** +*** 9322,9355 **** fx.mo:Expected error in mat fxbit-field: "fxbit-field: is not a valid end index". fx.mo:Expected error in mat fxbit-field: "fxbit-field: is not a valid start index". fx.mo:Expected error in mat fxbit-field: "fxbit-field: is not a valid end index". @@ -5196,7 +5234,7 @@ fx.mo:Expected error in mat fxif: "fxif: a is not a fixnum". fx.mo:Expected error in mat fxif: "fxif: 3.4 is not a fixnum". fx.mo:Expected error in mat fxif: "fxif: (a) is not a fixnum". ---- 9304,9337 ---- +--- 9322,9355 ---- fx.mo:Expected error in mat fxbit-field: "fxbit-field: is not a valid end index". fx.mo:Expected error in mat fxbit-field: "fxbit-field: is not a valid start index". fx.mo:Expected error in mat fxbit-field: "fxbit-field: is not a valid end index". @@ -5232,7 +5270,7 @@ fx.mo:Expected error in mat fxif: "fxif: 3.4 is not a fixnum". fx.mo:Expected error in mat fxif: "fxif: (a) is not a fixnum". *************** -*** 9341,9384 **** +*** 9359,9402 **** fx.mo:Expected error in mat fxif: "fxif: <-int> is not a fixnum". fx.mo:Expected error in mat fxif: "fxif: <-int> is not a fixnum". fx.mo:Expected error in mat fxif: "fxif: <-int> is not a fixnum". @@ -5277,7 +5315,7 @@ fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: 3.4 is not a fixnum". fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: "3" is not a fixnum". fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: is not a fixnum". ---- 9341,9384 ---- +--- 9359,9402 ---- fx.mo:Expected error in mat fxif: "fxif: <-int> is not a fixnum". fx.mo:Expected error in mat fxif: "fxif: <-int> is not a fixnum". fx.mo:Expected error in mat fxif: "fxif: <-int> is not a fixnum". @@ -5323,7 +5361,7 @@ fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: "3" is not a fixnum". fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: is not a fixnum". *************** -*** 9387,9397 **** +*** 9405,9415 **** fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: invalid bit index -1". fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: invalid bit index ". fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: invalid bit index ". @@ -5335,7 +5373,7 @@ fx.mo:Expected error in mat fxcopy-bit-field: "fxcopy-bit-field: "3" is not a fixnum". fx.mo:Expected error in mat fxcopy-bit-field: "fxcopy-bit-field: 3.4 is not a valid start index". fx.mo:Expected error in mat fxcopy-bit-field: "fxcopy-bit-field: 3/4 is not a valid end index". ---- 9387,9397 ---- +--- 9405,9415 ---- fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: invalid bit index -1". fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: invalid bit index ". fx.mo:Expected error in mat fxcopy-bit: "fxcopy-bit: invalid bit index ". @@ -5348,7 +5386,7 @@ fx.mo:Expected error in mat fxcopy-bit-field: "fxcopy-bit-field: 3.4 is not a valid start index". fx.mo:Expected error in mat fxcopy-bit-field: "fxcopy-bit-field: 3/4 is not a valid end index". *************** -*** 9451,9460 **** +*** 9469,9478 **** fx.mo:Expected error in mat fxdiv0-and-mod0: "fxmod0: (a) is not a fixnum". fx.mo:Expected error in mat fxdiv0-and-mod0: "fxmod0: undefined for 0". fx.mo:Expected error in mat fxdiv0-and-mod0: "fxmod0: undefined for 0". @@ -5359,7 +5397,7 @@ fx.mo:Expected error in mat fx+/carry: "fx+/carry: 1.0 is not a fixnum". fx.mo:Expected error in mat fx+/carry: "fx+/carry: 2.0 is not a fixnum". fx.mo:Expected error in mat fx+/carry: "fx+/carry: 3.0 is not a fixnum". ---- 9451,9460 ---- +--- 9469,9478 ---- fx.mo:Expected error in mat fxdiv0-and-mod0: "fxmod0: (a) is not a fixnum". fx.mo:Expected error in mat fxdiv0-and-mod0: "fxmod0: undefined for 0". fx.mo:Expected error in mat fxdiv0-and-mod0: "fxmod0: undefined for 0". @@ -5371,7 +5409,7 @@ fx.mo:Expected error in mat fx+/carry: "fx+/carry: 2.0 is not a fixnum". fx.mo:Expected error in mat fx+/carry: "fx+/carry: 3.0 is not a fixnum". *************** -*** 9470,9479 **** +*** 9488,9497 **** fx.mo:Expected error in mat fx+/carry: "fx+/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx+/carry: "fx+/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx+/carry: "fx+/carry: <-int> is not a fixnum". @@ -5382,7 +5420,7 @@ fx.mo:Expected error in mat fx-/carry: "fx-/carry: 1.0 is not a fixnum". fx.mo:Expected error in mat fx-/carry: "fx-/carry: 2.0 is not a fixnum". fx.mo:Expected error in mat fx-/carry: "fx-/carry: 3.0 is not a fixnum". ---- 9470,9479 ---- +--- 9488,9497 ---- fx.mo:Expected error in mat fx+/carry: "fx+/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx+/carry: "fx+/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx+/carry: "fx+/carry: <-int> is not a fixnum". @@ -5394,7 +5432,7 @@ fx.mo:Expected error in mat fx-/carry: "fx-/carry: 2.0 is not a fixnum". fx.mo:Expected error in mat fx-/carry: "fx-/carry: 3.0 is not a fixnum". *************** -*** 9489,9498 **** +*** 9507,9516 **** fx.mo:Expected error in mat fx-/carry: "fx-/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx-/carry: "fx-/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx-/carry: "fx-/carry: <-int> is not a fixnum". @@ -5405,7 +5443,7 @@ fx.mo:Expected error in mat fx*/carry: "fx*/carry: 1.0 is not a fixnum". fx.mo:Expected error in mat fx*/carry: "fx*/carry: 2.0 is not a fixnum". fx.mo:Expected error in mat fx*/carry: "fx*/carry: 3.0 is not a fixnum". ---- 9489,9498 ---- +--- 9507,9516 ---- fx.mo:Expected error in mat fx-/carry: "fx-/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx-/carry: "fx-/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx-/carry: "fx-/carry: <-int> is not a fixnum". @@ -5417,7 +5455,7 @@ fx.mo:Expected error in mat fx*/carry: "fx*/carry: 2.0 is not a fixnum". fx.mo:Expected error in mat fx*/carry: "fx*/carry: 3.0 is not a fixnum". *************** -*** 9508,9518 **** +*** 9526,9536 **** fx.mo:Expected error in mat fx*/carry: "fx*/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx*/carry: "fx*/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx*/carry: "fx*/carry: <-int> is not a fixnum". @@ -5429,7 +5467,7 @@ fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: a is not a fixnum". fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: invalid start index 0.0". fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: invalid end index 2.0". ---- 9508,9518 ---- +--- 9526,9536 ---- fx.mo:Expected error in mat fx*/carry: "fx*/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx*/carry: "fx*/carry: <-int> is not a fixnum". fx.mo:Expected error in mat fx*/carry: "fx*/carry: <-int> is not a fixnum". @@ -5442,7 +5480,7 @@ fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: invalid start index 0.0". fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: invalid end index 2.0". *************** -*** 9535,9544 **** +*** 9553,9562 **** fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: invalid end index ". fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: invalid end index ". fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: count 1 is greater than difference between end index 5 and start index 5". @@ -5453,7 +5491,7 @@ fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: a is not a fixnum". fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: invalid start index 0.0". fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: invalid end index 2.0". ---- 9535,9544 ---- +--- 9553,9562 ---- fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: invalid end index ". fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: invalid end index ". fx.mo:Expected error in mat fxrotate-bit-field: "fxrotate-bit-field: count 1 is greater than difference between end index 5 and start index 5". @@ -5465,7 +5503,7 @@ fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: invalid start index 0.0". fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: invalid end index 2.0". *************** -*** 9554,9571 **** +*** 9572,9589 **** fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: invalid end index ". fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: invalid end index <-int>". fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: start index 7 is greater than end index 5". @@ -5484,7 +5522,7 @@ fl.mo:Expected error in mat fl=: "fl=: (a) is not a flonum". fl.mo:Expected error in mat fl=: "fl=: a is not a flonum". fl.mo:Expected error in mat fl=: "fl=: a is not a flonum". ---- 9554,9571 ---- +--- 9572,9589 ---- fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: invalid end index ". fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: invalid end index <-int>". fx.mo:Expected error in mat fxreverse-bit-field: "fxreverse-bit-field: start index 7 is greater than end index 5". @@ -5504,7 +5542,7 @@ fl.mo:Expected error in mat fl=: "fl=: a is not a flonum". fl.mo:Expected error in mat fl=: "fl=: a is not a flonum". *************** -*** 9573,9579 **** +*** 9591,9597 **** fl.mo:Expected error in mat fl=: "fl=: 3 is not a flonum". fl.mo:Expected error in mat fl=: "fl=: 7/2 is not a flonum". fl.mo:Expected error in mat fl=: "fl=: 7/2 is not a flonum". @@ -5512,7 +5550,7 @@ fl.mo:Expected error in mat fl<: "fl<: (a) is not a flonum". fl.mo:Expected error in mat fl<: "fl<: a is not a flonum". fl.mo:Expected error in mat fl<: "fl<: a is not a flonum". ---- 9573,9579 ---- +--- 9591,9597 ---- fl.mo:Expected error in mat fl=: "fl=: 3 is not a flonum". fl.mo:Expected error in mat fl=: "fl=: 7/2 is not a flonum". fl.mo:Expected error in mat fl=: "fl=: 7/2 is not a flonum". @@ -5521,7 +5559,7 @@ fl.mo:Expected error in mat fl<: "fl<: a is not a flonum". fl.mo:Expected error in mat fl<: "fl<: a is not a flonum". *************** -*** 9581,9587 **** +*** 9599,9605 **** fl.mo:Expected error in mat fl<: "fl<: 3 is not a flonum". fl.mo:Expected error in mat fl<: "fl<: 7/2 is not a flonum". fl.mo:Expected error in mat fl<: "fl<: 7/2 is not a flonum". @@ -5529,7 +5567,7 @@ fl.mo:Expected error in mat fl>: "fl>: (a) is not a flonum". fl.mo:Expected error in mat fl>: "fl>: a is not a flonum". fl.mo:Expected error in mat fl>: "fl>: a is not a flonum". ---- 9581,9587 ---- +--- 9599,9605 ---- fl.mo:Expected error in mat fl<: "fl<: 3 is not a flonum". fl.mo:Expected error in mat fl<: "fl<: 7/2 is not a flonum". fl.mo:Expected error in mat fl<: "fl<: 7/2 is not a flonum". @@ -5538,7 +5576,7 @@ fl.mo:Expected error in mat fl>: "fl>: a is not a flonum". fl.mo:Expected error in mat fl>: "fl>: a is not a flonum". *************** -*** 9589,9595 **** +*** 9607,9613 **** fl.mo:Expected error in mat fl>: "fl>: 3 is not a flonum". fl.mo:Expected error in mat fl>: "fl>: 7/2 is not a flonum". fl.mo:Expected error in mat fl>: "fl>: 7/2 is not a flonum". @@ -5546,7 +5584,7 @@ fl.mo:Expected error in mat fl<=: "fl<=: (a) is not a flonum". fl.mo:Expected error in mat fl<=: "fl<=: a is not a flonum". fl.mo:Expected error in mat fl<=: "fl<=: a is not a flonum". ---- 9589,9595 ---- +--- 9607,9613 ---- fl.mo:Expected error in mat fl>: "fl>: 3 is not a flonum". fl.mo:Expected error in mat fl>: "fl>: 7/2 is not a flonum". fl.mo:Expected error in mat fl>: "fl>: 7/2 is not a flonum". @@ -5555,7 +5593,7 @@ fl.mo:Expected error in mat fl<=: "fl<=: a is not a flonum". fl.mo:Expected error in mat fl<=: "fl<=: a is not a flonum". *************** -*** 9597,9603 **** +*** 9615,9621 **** fl.mo:Expected error in mat fl<=: "fl<=: 3 is not a flonum". fl.mo:Expected error in mat fl<=: "fl<=: 7/2 is not a flonum". fl.mo:Expected error in mat fl<=: "fl<=: 7/2 is not a flonum". @@ -5563,7 +5601,7 @@ fl.mo:Expected error in mat fl>=: "fl>=: (a) is not a flonum". fl.mo:Expected error in mat fl>=: "fl>=: a is not a flonum". fl.mo:Expected error in mat fl>=: "fl>=: a is not a flonum". ---- 9597,9603 ---- +--- 9615,9621 ---- fl.mo:Expected error in mat fl<=: "fl<=: 3 is not a flonum". fl.mo:Expected error in mat fl<=: "fl<=: 7/2 is not a flonum". fl.mo:Expected error in mat fl<=: "fl<=: 7/2 is not a flonum". @@ -5572,7 +5610,7 @@ fl.mo:Expected error in mat fl>=: "fl>=: a is not a flonum". fl.mo:Expected error in mat fl>=: "fl>=: a is not a flonum". *************** -*** 9605,9644 **** +*** 9623,9662 **** fl.mo:Expected error in mat fl>=: "fl>=: 3 is not a flonum". fl.mo:Expected error in mat fl>=: "fl>=: 7/2 is not a flonum". fl.mo:Expected error in mat fl>=: "fl>=: 7/2 is not a flonum". @@ -5613,7 +5651,7 @@ fl.mo:Expected error in mat fl>=?: "fl>=?: a is not a flonum". fl.mo:Expected error in mat fl>=?: "fl>=?: a is not a flonum". fl.mo:Expected error in mat fl>=?: "fl>=?: 3 is not a flonum". ---- 9605,9644 ---- +--- 9623,9662 ---- fl.mo:Expected error in mat fl>=: "fl>=: 3 is not a flonum". fl.mo:Expected error in mat fl>=: "fl>=: 7/2 is not a flonum". fl.mo:Expected error in mat fl>=: "fl>=: 7/2 is not a flonum". @@ -5655,7 +5693,7 @@ fl.mo:Expected error in mat fl>=?: "fl>=?: a is not a flonum". fl.mo:Expected error in mat fl>=?: "fl>=?: 3 is not a flonum". *************** -*** 9648,9654 **** +*** 9666,9672 **** fl.mo:Expected error in mat fl+: "fl+: (a . b) is not a flonum". fl.mo:Expected error in mat fl+: "fl+: 1 is not a flonum". fl.mo:Expected error in mat fl+: "fl+: 2/3 is not a flonum". @@ -5663,7 +5701,7 @@ fl.mo:Expected error in mat fl-: "fl-: (a . b) is not a flonum". fl.mo:Expected error in mat fl-: "fl-: 1 is not a flonum". fl.mo:Expected error in mat fl-: "fl-: a is not a flonum". ---- 9648,9654 ---- +--- 9666,9672 ---- fl.mo:Expected error in mat fl+: "fl+: (a . b) is not a flonum". fl.mo:Expected error in mat fl+: "fl+: 1 is not a flonum". fl.mo:Expected error in mat fl+: "fl+: 2/3 is not a flonum". @@ -5672,7 +5710,7 @@ fl.mo:Expected error in mat fl-: "fl-: 1 is not a flonum". fl.mo:Expected error in mat fl-: "fl-: a is not a flonum". *************** -*** 9658,9740 **** +*** 9676,9758 **** fl.mo:Expected error in mat fl*: "fl*: (a . b) is not a flonum". fl.mo:Expected error in mat fl*: "fl*: 1 is not a flonum". fl.mo:Expected error in mat fl*: "fl*: 2/3 is not a flonum". @@ -5756,7 +5794,7 @@ fl.mo:Expected error in mat flround: "flround: a is not a flonum". fl.mo:Expected error in mat flround: "flround: 2.0+1.0i is not a flonum". fl.mo:Expected error in mat flround: "flround: 2+1i is not a flonum". ---- 9658,9740 ---- +--- 9676,9758 ---- fl.mo:Expected error in mat fl*: "fl*: (a . b) is not a flonum". fl.mo:Expected error in mat fl*: "fl*: 1 is not a flonum". fl.mo:Expected error in mat fl*: "fl*: 2/3 is not a flonum". @@ -5841,7 +5879,7 @@ fl.mo:Expected error in mat flround: "flround: 2.0+1.0i is not a flonum". fl.mo:Expected error in mat flround: "flround: 2+1i is not a flonum". *************** -*** 9754,9789 **** +*** 9772,9807 **** fl.mo:Expected error in mat flinfinite?: "flinfinite?: 3 is not a flonum". fl.mo:Expected error in mat flinfinite?: "flinfinite?: 3/4 is not a flonum". fl.mo:Expected error in mat flinfinite?: "flinfinite?: hi is not a flonum". @@ -5878,7 +5916,7 @@ fl.mo:Expected error in mat fleven?: "fleven?: a is not a flonum". fl.mo:Expected error in mat fleven?: "fleven?: 3 is not a flonum". fl.mo:Expected error in mat fleven?: "fleven?: 3.2 is not an integer". ---- 9754,9789 ---- +--- 9772,9807 ---- fl.mo:Expected error in mat flinfinite?: "flinfinite?: 3 is not a flonum". fl.mo:Expected error in mat flinfinite?: "flinfinite?: 3/4 is not a flonum". fl.mo:Expected error in mat flinfinite?: "flinfinite?: hi is not a flonum". @@ -5916,7 +5954,7 @@ fl.mo:Expected error in mat fleven?: "fleven?: 3 is not a flonum". fl.mo:Expected error in mat fleven?: "fleven?: 3.2 is not an integer". *************** -*** 9791,9798 **** +*** 9809,9816 **** fl.mo:Expected error in mat fleven?: "fleven?: 1+1i is not a flonum". fl.mo:Expected error in mat fleven?: "fleven?: +inf.0 is not an integer". fl.mo:Expected error in mat fleven?: "fleven?: +nan.0 is not an integer". @@ -5925,7 +5963,7 @@ fl.mo:Expected error in mat flodd?: "flodd?: a is not a flonum". fl.mo:Expected error in mat flodd?: "flodd?: 3 is not a flonum". fl.mo:Expected error in mat flodd?: "flodd?: 3.2 is not an integer". ---- 9791,9798 ---- +--- 9809,9816 ---- fl.mo:Expected error in mat fleven?: "fleven?: 1+1i is not a flonum". fl.mo:Expected error in mat fleven?: "fleven?: +inf.0 is not an integer". fl.mo:Expected error in mat fleven?: "fleven?: +nan.0 is not an integer". @@ -5935,7 +5973,7 @@ fl.mo:Expected error in mat flodd?: "flodd?: 3 is not a flonum". fl.mo:Expected error in mat flodd?: "flodd?: 3.2 is not an integer". *************** -*** 9800,9806 **** +*** 9818,9824 **** fl.mo:Expected error in mat flodd?: "flodd?: 3+1i is not a flonum". fl.mo:Expected error in mat flodd?: "flodd?: +inf.0 is not an integer". fl.mo:Expected error in mat flodd?: "flodd?: +nan.0 is not an integer". @@ -5943,7 +5981,7 @@ fl.mo:Expected error in mat flmin: "flmin: a is not a flonum". fl.mo:Expected error in mat flmin: "flmin: a is not a flonum". fl.mo:Expected error in mat flmin: "flmin: a is not a flonum". ---- 9800,9806 ---- +--- 9818,9824 ---- fl.mo:Expected error in mat flodd?: "flodd?: 3+1i is not a flonum". fl.mo:Expected error in mat flodd?: "flodd?: +inf.0 is not an integer". fl.mo:Expected error in mat flodd?: "flodd?: +nan.0 is not an integer". @@ -5952,7 +5990,7 @@ fl.mo:Expected error in mat flmin: "flmin: a is not a flonum". fl.mo:Expected error in mat flmin: "flmin: a is not a flonum". *************** -*** 9808,9814 **** +*** 9826,9832 **** fl.mo:Expected error in mat flmin: "flmin: a is not a flonum". fl.mo:Expected error in mat flmin: "flmin: 0.0+1.0i is not a flonum". fl.mo:Expected error in mat flmin: "flmin: 0+1i is not a flonum". @@ -5960,7 +5998,7 @@ fl.mo:Expected error in mat flmax: "flmax: a is not a flonum". fl.mo:Expected error in mat flmax: "flmax: a is not a flonum". fl.mo:Expected error in mat flmax: "flmax: 3 is not a flonum". ---- 9808,9814 ---- +--- 9826,9832 ---- fl.mo:Expected error in mat flmin: "flmin: a is not a flonum". fl.mo:Expected error in mat flmin: "flmin: 0.0+1.0i is not a flonum". fl.mo:Expected error in mat flmin: "flmin: 0+1i is not a flonum". @@ -5969,7 +6007,7 @@ fl.mo:Expected error in mat flmax: "flmax: a is not a flonum". fl.mo:Expected error in mat flmax: "flmax: 3 is not a flonum". *************** -*** 9816,9829 **** +*** 9834,9847 **** fl.mo:Expected error in mat flmax: "flmax: a is not a flonum". fl.mo:Expected error in mat flmax: "flmax: 0.0+1.0i is not a flonum". fl.mo:Expected error in mat flmax: "flmax: 0+1i is not a flonum". @@ -5984,7 +6022,7 @@ fl.mo:Expected error in mat fldenominator: "fldenominator: a is not a flonum". fl.mo:Expected error in mat fldenominator: "fldenominator: 3 is not a flonum". fl.mo:Expected error in mat fldenominator: "fldenominator: 0+1i is not a flonum". ---- 9816,9829 ---- +--- 9834,9847 ---- fl.mo:Expected error in mat flmax: "flmax: a is not a flonum". fl.mo:Expected error in mat flmax: "flmax: 0.0+1.0i is not a flonum". fl.mo:Expected error in mat flmax: "flmax: 0+1i is not a flonum". @@ -6000,7 +6038,7 @@ fl.mo:Expected error in mat fldenominator: "fldenominator: 3 is not a flonum". fl.mo:Expected error in mat fldenominator: "fldenominator: 0+1i is not a flonum". *************** -*** 9869,9875 **** +*** 9887,9893 **** cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". @@ -6008,7 +6046,7 @@ cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". ---- 9869,9875 ---- +--- 9887,9893 ---- cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". @@ -6017,7 +6055,7 @@ cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". cfl.mo:Expected error in mat cfl-: "cfl-: a is not a cflonum". *************** -*** 9879,9892 **** +*** 9897,9910 **** cfl.mo:Expected error in mat cfl/: "cfl/: a is not a cflonum". cfl.mo:Expected error in mat cfl/: "cfl/: a is not a cflonum". cfl.mo:Expected error in mat cfl/: "cfl/: a is not a cflonum". @@ -6032,7 +6070,7 @@ foreign.mo:Expected error in mat load-shared-object: "load-shared-object: invalid path 3". foreign.mo:Expected error in mat foreign-procedure: "foreign-procedure: no entry for "i do not exist"". foreign.mo:Expected error in mat foreign-procedure: "foreign-procedure: no entry for "i do not exist"". ---- 9879,9892 ---- +--- 9897,9910 ---- cfl.mo:Expected error in mat cfl/: "cfl/: a is not a cflonum". cfl.mo:Expected error in mat cfl/: "cfl/: a is not a cflonum". cfl.mo:Expected error in mat cfl/: "cfl/: a is not a cflonum". @@ -6048,7 +6086,7 @@ foreign.mo:Expected error in mat foreign-procedure: "foreign-procedure: no entry for "i do not exist"". foreign.mo:Expected error in mat foreign-procedure: "foreign-procedure: no entry for "i do not exist"". *************** -*** 9921,9928 **** +*** 9939,9946 **** foreign.mo:Expected error in mat foreign-procedure: "id: invalid foreign-procedure argument foo". foreign.mo:Expected error in mat foreign-procedure: "foreign-procedure: invalid foreign procedure handle abcde". foreign.mo:Expected error in mat foreign-procedure: "float_id: invalid foreign-procedure argument 0". @@ -6057,7 +6095,7 @@ foreign.mo:Expected error in mat foreign-sizeof: "foreign-sizeof: invalid foreign type specifier i-am-not-a-type". foreign.mo:Expected error in mat foreign-sizeof: "foreign-sizeof: invalid foreign type specifier 1". foreign.mo:Expected error in mat foreign-bytevectors: "u8*->u8*: invalid foreign-procedure argument "hello"". ---- 9921,9928 ---- +--- 9939,9946 ---- foreign.mo:Expected error in mat foreign-procedure: "id: invalid foreign-procedure argument foo". foreign.mo:Expected error in mat foreign-procedure: "foreign-procedure: invalid foreign procedure handle abcde". foreign.mo:Expected error in mat foreign-procedure: "float_id: invalid foreign-procedure argument 0". @@ -6067,7 +6105,7 @@ foreign.mo:Expected error in mat foreign-sizeof: "foreign-sizeof: invalid foreign type specifier 1". foreign.mo:Expected error in mat foreign-bytevectors: "u8*->u8*: invalid foreign-procedure argument "hello"". *************** -*** 10420,10432 **** +*** 10438,10450 **** unix.mo:Expected error in mat file-operations: "file-access-time: failed for "testlink": no such file or directory". unix.mo:Expected error in mat file-operations: "file-change-time: failed for "testlink": no such file or directory". unix.mo:Expected error in mat file-operations: "file-modification-time: failed for "testlink": no such file or directory". @@ -6081,7 +6119,7 @@ windows.mo:Expected error in mat registry: "get-registry: pooh is not a string". windows.mo:Expected error in mat registry: "put-registry!: 3 is not a string". windows.mo:Expected error in mat registry: "put-registry!: 3 is not a string". ---- 10420,10432 ---- +--- 10438,10450 ---- unix.mo:Expected error in mat file-operations: "file-access-time: failed for "testlink": no such file or directory". unix.mo:Expected error in mat file-operations: "file-change-time: failed for "testlink": no such file or directory". unix.mo:Expected error in mat file-operations: "file-modification-time: failed for "testlink": no such file or directory". @@ -6096,7 +6134,7 @@ windows.mo:Expected error in mat registry: "put-registry!: 3 is not a string". windows.mo:Expected error in mat registry: "put-registry!: 3 is not a string". *************** -*** 10454,10525 **** +*** 10472,10543 **** ieee.mo:Expected error in mat flonum->fixnum: "flonum->fixnum: result for -inf.0 would be outside of fixnum range". ieee.mo:Expected error in mat flonum->fixnum: "flonum->fixnum: result for +nan.0 would be outside of fixnum range". ieee.mo:Expected error in mat fllp: "fllp: 3 is not a flonum". @@ -6169,7 +6207,7 @@ date.mo:Expected error in mat time: "time>=?: 3 is not a time record". date.mo:Expected error in mat time: "time>=?: # is not a time record". date.mo:Expected error in mat time: "time>=?: types of