1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
/* Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees.
See file COPYING. */
/* Implements area_roots.h */
#include <stdlib.h>
#include "scheme48.h"
#include "area_roots.h"
#include "areas.h"
#include "memory.h"
#include "memory_map.h"
#include "utils.h"
#include "data.h"
#include "measure.h"
#include "generation_gc.h"
#include "gc_config.h"
#if (S48_USE_REMEMBERED_SETS)
#include "remset.h"
#endif
/* initializes the dirty vector of AREA */
void s48_init_dirty_vector(Area* area) {
Dirty_vector* dv = &area->dirty_vector;
unsigned long area_size = area->end - area->start;
/* The number of logical cards is the division of area_size through
the logical card_size (number of 32-bit-addresses). Bitwise Division:
shift right */
unsigned long number_of_cards = area_size >> S48_LOG_CARD_SIZE ;
dv->length = number_of_cards;
/* Space allocation and initialisation */
#if S48_DIRTY_VECTOR_METHOD==S48_OFFSET_DIRTY_VECTORS
/* A vector of bytes (offset is max 2^9 - 1 = 511 => max logical card size = 9) */
dv->items = (char*)calloc(sizeof(char), number_of_cards);
#endif
#if S48_DIRTY_VECTOR_METHOD==S48_ADDRESS_DIRTY_VECTORS
/* A vector of double words */
dv->items = (s48_address*)calloc(sizeof(s48_address), number_of_cards);
#endif
#if S48_DIRTY_VECTOR_METHOD==S48_CROSSINGMAP_DIRTY_VECTORS
/* This method uses two bits per card. One bit marks a card as
beeing dirty, the second marks a card as beeing tracable, which
means that the card does not begin within a B-vector (A string
for example). We use a full char to store the bit. */
dv->dirty_bits = (char*)calloc(sizeof(char), number_of_cards);
dv->traceable_bits = (char*)calloc(sizeof(char), number_of_cards);
dv->last_frontier = area->frontier;
#endif
#if (S48_USE_CARD_GENERATION_INDEXING)
dv->minimum_index = (unsigned char*)malloc(sizeof(char) * number_of_cards);
for (i = 0; i < number_of_cards; i++)
dv->minimum_index[i] = 255;
#endif
}
/* deinitializes the dirty vector of AREA. (should free the memory
allocated in init_dirty_vector */
void s48_deinit_dirty_vector(Area* area) {
Dirty_vector* dv = &area->dirty_vector;
#if S48_DIRTY_VECTOR_METHOD==S48_OFFSET_DIRTY_VECTORS
free(dv->items);
#endif
#if S48_DIRTY_VECTOR_METHOD==S48_ADDRESS_DIRTY_VECTORS
free(dv->items);
#endif
#if S48_DIRTY_VECTOR_METHOD==S48_CROSSINGMAP_DIRTY_VECTORS
free(dv->dirty_bits);
free(dv->traceable_bits);
#endif
}
#if (MEASURE_GC)
static unsigned long areas_visited = 0;
static unsigned long areas_passed = 0;
#endif
/* FPage 9 */
/* passes all dirty regions in all areas in the linked list starting
with AREAS, to trace_locationsB */
void s48_trace_areas_roots(Area* areas, int generations_count) {
while(areas != NULL) {
Dirty_vector* dirty_vector = &areas->dirty_vector;
s48_address frontier = areas->frontier;
s48_address card_start_address = areas->start;
s48_address start_address, end_address;
int i;
#if S48_DIRTY_VECTOR_METHOD==S48_CROSSINGMAP_DIRTY_VECTORS
/* This method uses two bits per card. One bit marks a card as
beeing dirty, the second marks a card as beeing tracable, which
means that the card does not begin within a B-vector (A string
for example). We use a full char to store the bit. */
char* dirty_bits = dirty_vector->dirty_bits;
char* traceable_bits = dirty_vector->traceable_bits;
/* if new objects were allocated since the last trace, then scan
the new part of the area to find out which of the new cards are
traceable */
s48_address start = areas->start;
s48_address addr = dirty_vector->last_frontier;
while (addr < frontier) {
s48_value v = *((s48_value*)addr);
unsigned long offset = addr - start;
if ((offset % S48_CARD_SIZE) == 0) {
traceable_bits[offset >> S48_LOG_CARD_SIZE] = TRUE;
}
else {
traceable_bits[offset >> S48_LOG_CARD_SIZE] = FALSE;
}
if (S48_B_VECTOR_HEADER_P(v))
addr = addr + S48_STOB_OVERHEAD_IN_A_UNITS +
S48_HEADER_LENGTH_IN_A_UNITS(v);
else
addr = S48_ADDRESS_INC(addr);
}
/* remember that we have looked at this part of the area */
dirty_vector->last_frontier = frontier;
#endif
#if (MEASURE_GC)
areas_visited += areas->frontier - areas->start;
#endif
/* MAIN SCANNING OF THE DIRTY VECTOR */
/* Search through the whole dirty_vector */
for (i = 0; i < dirty_vector->length;
i++, card_start_address += S48_CARD_SIZE) {
#if (S48_USE_CARD_GENERATION_INDEXING)
/* we can skip this card, if it doesn't contain pointers to a
generation that we're collected right now. */
if (dirty_vector->minimum_index[i] >= generations_count)
continue;
#endif
#if S48_DIRTY_VECTOR_METHOD==S48_OFFSET_DIRTY_VECTORS
dirty_byte = dirty_vector->items[i];
if (dirty_byte != 0) {
/* Get the relative offset in addressable units to the start
address of the i-th card */
unsigned char card_offset = dirty_byte >> 1;
/* Get the absolute start_address and end_address of the i-th
card */
start_address = card_start_address + S48_CELLS_TO_BYTES(card_offset);
end_address = card_start_address + S48_CARD_SIZE;
/* reset to 0. internal_write_barrier will be called to mark
the still dirty cards. */
dirty_vector->items[i] = 0;
#endif
#if S48_DIRTY_VECTOR_METHOD==S48_ADDRESS_DIRTY_VECTORS
start_address = dirty_vector->items[i];
if (start_address != NULL) {
end_address = card_start_address + S48_CARD_SIZE;
dirty_vector->items[i] = NULL;
#endif
#if S48_DIRTY_VECTOR_METHOD==S48_CROSSINGMAP_DIRTY_VECTORS
if (dirty_bits[i]) {
int j = i;
/* search backwards for a traceable card (the first one must
be a traceable one). */
start_address = card_start_address;
end_address = card_start_address + S48_CARD_SIZE;
while ((j > 0) && (!traceable_bits[j])) {
j--;
start_address = start_address - S48_CARD_SIZE;
}
dirty_bits[i] = FALSE;
/* a possible optimization would be to avoid tracing a card
twice completely, e.g. by tracing backwards from the end to
beginning, or to search forward for more consecutive dirty
cards. */
#endif
#if (S48_USE_CARD_GENERATION_INDEXING)
/* clear the minimum_index too */
dirty_vector->minimum_index[i] = 255;
#endif
/* adjust/control addresses */
if (end_address > frontier) end_address = frontier;
if (start_address > frontier)
/* i'm not sure if this just has to be ignored... */
s48_gc_error("s48_trace_areas_roots: dirty bit set behind frontier.");
#if (MEASURE_GC)
areas_passed += (end_address - start_address);
#endif
s48_internal_trace_locationsB(areas, start_address, end_address, "s48_trace_areas_roots");
}
}
areas = areas->next;
}
#if (MEASURE_GC)
measure_areas_roots(areas_visited, areas_passed);
areas_visited = 0;
areas_passed = 0;
#endif
}
void s48_set_dirty_vector(Area* area, s48_address addr, long stob,
Area* maybe_to_area) {
s48_set_dirty_vector_inline(area, addr, stob, maybe_to_area);
}
void s48_write_barrier(long stob, s48_address address, long value) {
s48_write_barrier_inline(stob, address, value);
}
|