- gc_assert(is_lisp_pointer(object));
-
- header = *((lispobj *) native_pointer(object));
- length = HeaderValue(header) + 1;
- length = CEILING(length, 2);
-
- return copy_large_unboxed_object(object, length);
-}
-#endif
-
-\f
-/*
- * Lutexes. Using the normal finalization machinery for finalizing
- * lutexes is tricky, since the finalization depends on working lutexes.
- * So we track the lutexes in the GC and finalize them manually.
- */
-
-#if defined(LUTEX_WIDETAG)
-
-/*
- * Start tracking LUTEX in the GC, by adding it to the linked list of
- * lutexes in the nursery generation. The caller is responsible for
- * locking, and GCs must be inhibited until the registration is
- * complete.
- */
-void
-gencgc_register_lutex (struct lutex *lutex) {
- int index = find_page_index(lutex);
- generation_index_t gen;
- struct lutex *head;
-
- /* This lutex is in static space, so we don't need to worry about
- * finalizing it.
- */
- if (index == -1)
- return;
-
- gen = page_table[index].gen;
-
- gc_assert(gen >= 0);
- gc_assert(gen < NUM_GENERATIONS);
-
- head = generations[gen].lutexes;
-
- lutex->gen = gen;
- lutex->next = head;
- lutex->prev = NULL;
- if (head)
- head->prev = lutex;
- generations[gen].lutexes = lutex;
-}
-
-/*
- * Stop tracking LUTEX in the GC by removing it from the appropriate
- * linked lists. This will only be called during GC, so no locking is
- * needed.
- */
-void
-gencgc_unregister_lutex (struct lutex *lutex) {
- if (lutex->prev) {
- lutex->prev->next = lutex->next;
- } else {
- generations[lutex->gen].lutexes = lutex->next;
- }
-
- if (lutex->next) {
- lutex->next->prev = lutex->prev;
- }
-
- lutex->next = NULL;
- lutex->prev = NULL;
- lutex->gen = -1;
-}
-
-/*
- * Mark all lutexes in generation GEN as not live.
- */
-static void
-unmark_lutexes (generation_index_t gen) {
- struct lutex *lutex = generations[gen].lutexes;
-
- while (lutex) {
- lutex->live = 0;
- lutex = lutex->next;
- }
-}
-
-/*
- * Finalize all lutexes in generation GEN that have not been marked live.
- */
-static void
-reap_lutexes (generation_index_t gen) {
- struct lutex *lutex = generations[gen].lutexes;
-
- while (lutex) {
- struct lutex *next = lutex->next;
- if (!lutex->live) {
- lutex_destroy((tagged_lutex_t) lutex);
- gencgc_unregister_lutex(lutex);
- }
- lutex = next;
- }
-}
-
-/*
- * Mark LUTEX as live.
- */
-static void
-mark_lutex (lispobj tagged_lutex) {
- struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
-
- lutex->live = 1;
-}
-
-/*
- * Move all lutexes in generation FROM to generation TO.
- */
-static void
-move_lutexes (generation_index_t from, generation_index_t to) {
- struct lutex *tail = generations[from].lutexes;
-
- /* Nothing to move */
- if (!tail)
- return;
-
- /* Change the generation of the lutexes in FROM. */
- while (tail->next) {
- tail->gen = to;
- tail = tail->next;
- }
- tail->gen = to;
-
- /* Link the last lutex in the FROM list to the start of the TO list */
- tail->next = generations[to].lutexes;
-
- /* And vice versa */
- if (generations[to].lutexes) {
- generations[to].lutexes->prev = tail;
- }
-
- /* And update the generations structures to match this */
- generations[to].lutexes = generations[from].lutexes;
- generations[from].lutexes = NULL;
-}
-
-static long
-scav_lutex(lispobj *where, lispobj object)
-{
- mark_lutex((lispobj) where);
-
- return CEILING(sizeof(struct lutex)/sizeof(lispobj), 2);
-}
-
-static lispobj
-trans_lutex(lispobj object)
-{
- struct lutex *lutex = (struct lutex *) native_pointer(object);
- lispobj copied;
- size_t words = CEILING(sizeof(struct lutex)/sizeof(lispobj), 2);
- gc_assert(is_lisp_pointer(object));
- copied = copy_object(object, words);
-
- /* Update the links, since the lutex moved in memory. */
- if (lutex->next) {
- lutex->next->prev = (struct lutex *) native_pointer(copied);
- }
-
- if (lutex->prev) {
- lutex->prev->next = (struct lutex *) native_pointer(copied);
- } else {
- generations[lutex->gen].lutexes =
- (struct lutex *) native_pointer(copied);
- }
-
- return copied;
-}
-
-static long
-size_lutex(lispobj *where)
-{
- return CEILING(sizeof(struct lutex)/sizeof(lispobj), 2);
-}
-#endif /* LUTEX_WIDETAG */
-
-\f
-/*
- * weak pointers
- */
-
-/* XX This is a hack adapted from cgc.c. These don't work too
- * efficiently with the gencgc as a list of the weak pointers is
- * maintained within the objects which causes writes to the pages. A
- * limited attempt is made to avoid unnecessary writes, but this needs
- * a re-think. */
-#define WEAK_POINTER_NWORDS \
- CEILING((sizeof(struct weak_pointer) / sizeof(lispobj)), 2)
-
-static long
-scav_weak_pointer(lispobj *where, lispobj object)
-{
- /* Since we overwrite the 'next' field, we have to make
- * sure not to do so for pointers already in the list.
- * Instead of searching the list of weak_pointers each
- * time, we ensure that next is always NULL when the weak
- * pointer isn't in the list, and not NULL otherwise.
- * Since we can't use NULL to denote end of list, we
- * use a pointer back to the same weak_pointer.
- */
- struct weak_pointer * wp = (struct weak_pointer*)where;
-
- if (NULL == wp->next) {
- wp->next = weak_pointers;
- weak_pointers = wp;
- if (NULL == wp->next)
- wp->next = wp;
- }
-
- /* Do not let GC scavenge the value slot of the weak pointer.
- * (That is why it is a weak pointer.) */
-
- return WEAK_POINTER_NWORDS;
-}
-
-\f
-lispobj *
-search_read_only_space(void *pointer)
-{
- lispobj *start = (lispobj *) READ_ONLY_SPACE_START;
- lispobj *end = (lispobj *) SymbolValue(READ_ONLY_SPACE_FREE_POINTER,0);
- if ((pointer < (void *)start) || (pointer >= (void *)end))
- return NULL;
- return (gc_search_space(start,
- (((lispobj *)pointer)+2)-start,
- (lispobj *) pointer));
-}
-
-lispobj *
-search_static_space(void *pointer)
-{
- lispobj *start = (lispobj *)STATIC_SPACE_START;
- lispobj *end = (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER,0);
- if ((pointer < (void *)start) || (pointer >= (void *)end))
- return NULL;
- return (gc_search_space(start,
- (((lispobj *)pointer)+2)-start,
- (lispobj *) pointer));
-}
-
-/* a faster version for searching the dynamic space. This will work even
- * if the object is in a current allocation region. */
-lispobj *
-search_dynamic_space(void *pointer)
-{
- page_index_t page_index = find_page_index(pointer);
- lispobj *start;
-
- /* The address may be invalid, so do some checks. */
- if ((page_index == -1) || page_free_p(page_index))
- return NULL;
- start = (lispobj *)page_region_start(page_index);
- return (gc_search_space(start,
- (((lispobj *)pointer)+2)-start,
- (lispobj *)pointer));
-}
-
-#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)
-
-/* Helper for valid_lisp_pointer_p and
- * possibly_valid_dynamic_space_pointer.
- *
- * pointer is the pointer to validate, and start_addr is the address
- * of the enclosing object.
- */
-static int
-looks_like_valid_lisp_pointer_p(lispobj *pointer, lispobj *start_addr)
-{
- if (!is_lisp_pointer((lispobj)pointer)) {
- return 0;
- }
-
- /* Check that the object pointed to is consistent with the pointer
- * low tag. */
- switch (lowtag_of((lispobj)pointer)) {
- case FUN_POINTER_LOWTAG:
- /* Start_addr should be the enclosing code object, or a closure
- * header. */
- switch (widetag_of(*start_addr)) {
- case CODE_HEADER_WIDETAG:
- /* This case is probably caught above. */
- break;
- case CLOSURE_HEADER_WIDETAG:
- case FUNCALLABLE_INSTANCE_HEADER_WIDETAG:
- if ((unsigned long)pointer !=
- ((unsigned long)start_addr+FUN_POINTER_LOWTAG)) {
- if (gencgc_verbose) {
- FSHOW((stderr,
- "/Wf2: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
- }
- break;
- default:
- if (gencgc_verbose) {
- FSHOW((stderr,
- "/Wf3: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
- }
- break;
- case LIST_POINTER_LOWTAG:
- if ((unsigned long)pointer !=
- ((unsigned long)start_addr+LIST_POINTER_LOWTAG)) {
- if (gencgc_verbose) {
- FSHOW((stderr,
- "/Wl1: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
- }
- /* Is it plausible cons? */
- if ((is_lisp_pointer(start_addr[0]) ||
- is_lisp_immediate(start_addr[0])) &&
- (is_lisp_pointer(start_addr[1]) ||
- is_lisp_immediate(start_addr[1])))
- break;
- else {
- if (gencgc_verbose) {
- FSHOW((stderr,
- "/Wl2: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
- }
- case INSTANCE_POINTER_LOWTAG:
- if ((unsigned long)pointer !=
- ((unsigned long)start_addr+INSTANCE_POINTER_LOWTAG)) {
- if (gencgc_verbose) {
- FSHOW((stderr,
- "/Wi1: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
- }
- if (widetag_of(start_addr[0]) != INSTANCE_HEADER_WIDETAG) {
- if (gencgc_verbose) {
- FSHOW((stderr,
- "/Wi2: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
- }
- break;
- case OTHER_POINTER_LOWTAG:
- if ((unsigned long)pointer !=
- ((unsigned long)start_addr+OTHER_POINTER_LOWTAG)) {
- if (gencgc_verbose) {
- FSHOW((stderr,
- "/Wo1: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
- }
- /* Is it plausible? Not a cons. XXX should check the headers. */
- if (is_lisp_pointer(start_addr[0]) || ((start_addr[0] & 3) == 0)) {
- if (gencgc_verbose) {
- FSHOW((stderr,
- "/Wo2: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
- }
- switch (widetag_of(start_addr[0])) {
- case UNBOUND_MARKER_WIDETAG:
- case NO_TLS_VALUE_MARKER_WIDETAG:
- case CHARACTER_WIDETAG:
-#if N_WORD_BITS == 64
- case SINGLE_FLOAT_WIDETAG:
-#endif
- if (gencgc_verbose) {
- FSHOW((stderr,
- "*Wo3: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
-
- /* only pointed to by function pointers? */
- case CLOSURE_HEADER_WIDETAG:
- case FUNCALLABLE_INSTANCE_HEADER_WIDETAG:
- if (gencgc_verbose) {
- FSHOW((stderr,
- "*Wo4: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
-
- case INSTANCE_HEADER_WIDETAG:
- if (gencgc_verbose) {
- FSHOW((stderr,
- "*Wo5: %x %x %x\n",
- pointer, start_addr, *start_addr));
- }
- return 0;
-
- /* the valid other immediate pointer objects */
- case SIMPLE_VECTOR_WIDETAG:
- case RATIO_WIDETAG:
- case COMPLEX_WIDETAG:
-#ifdef COMPLEX_SINGLE_FLOAT_WIDETAG
- case COMPLEX_SINGLE_FLOAT_WIDETAG:
-#endif
-#ifdef COMPLEX_DOUBLE_FLOAT_WIDETAG
- case COMPLEX_DOUBLE_FLOAT_WIDETAG:
-#endif
-#ifdef COMPLEX_LONG_FLOAT_WIDETAG
- case COMPLEX_LONG_FLOAT_WIDETAG:
-#endif
- case SIMPLE_ARRAY_WIDETAG:
- case COMPLEX_BASE_STRING_WIDETAG:
-#ifdef COMPLEX_CHARACTER_STRING_WIDETAG
- case COMPLEX_CHARACTER_STRING_WIDETAG:
-#endif
- case COMPLEX_VECTOR_NIL_WIDETAG:
- case COMPLEX_BIT_VECTOR_WIDETAG:
- case COMPLEX_VECTOR_WIDETAG:
- case COMPLEX_ARRAY_WIDETAG:
- case VALUE_CELL_HEADER_WIDETAG:
- case SYMBOL_HEADER_WIDETAG:
- case FDEFN_WIDETAG:
- case CODE_HEADER_WIDETAG:
- case BIGNUM_WIDETAG:
-#if N_WORD_BITS != 64
- case SINGLE_FLOAT_WIDETAG:
-#endif
- case DOUBLE_FLOAT_WIDETAG:
-#ifdef LONG_FLOAT_WIDETAG
- case LONG_FLOAT_WIDETAG:
-#endif
- case SIMPLE_BASE_STRING_WIDETAG:
-#ifdef SIMPLE_CHARACTER_STRING_WIDETAG
- case SIMPLE_CHARACTER_STRING_WIDETAG:
-#endif
- case SIMPLE_BIT_VECTOR_WIDETAG:
- case SIMPLE_ARRAY_NIL_WIDETAG:
- case SIMPLE_ARRAY_UNSIGNED_BYTE_2_WIDETAG:
- case SIMPLE_ARRAY_UNSIGNED_BYTE_4_WIDETAG:
- case SIMPLE_ARRAY_UNSIGNED_BYTE_7_WIDETAG:
- case SIMPLE_ARRAY_UNSIGNED_BYTE_8_WIDETAG:
- case SIMPLE_ARRAY_UNSIGNED_BYTE_15_WIDETAG:
- case SIMPLE_ARRAY_UNSIGNED_BYTE_16_WIDETAG:
-#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_29_WIDETAG
- case SIMPLE_ARRAY_UNSIGNED_BYTE_29_WIDETAG:
-#endif
- case SIMPLE_ARRAY_UNSIGNED_BYTE_31_WIDETAG:
- case SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG:
-#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG
- case SIMPLE_ARRAY_UNSIGNED_BYTE_60_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG
- case SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_64_WIDETAG
- case SIMPLE_ARRAY_UNSIGNED_BYTE_64_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_SIGNED_BYTE_8_WIDETAG
- case SIMPLE_ARRAY_SIGNED_BYTE_8_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_SIGNED_BYTE_16_WIDETAG
- case SIMPLE_ARRAY_SIGNED_BYTE_16_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_SIGNED_BYTE_30_WIDETAG
- case SIMPLE_ARRAY_SIGNED_BYTE_30_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_SIGNED_BYTE_32_WIDETAG
- case SIMPLE_ARRAY_SIGNED_BYTE_32_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_SIGNED_BYTE_61_WIDETAG
- case SIMPLE_ARRAY_SIGNED_BYTE_61_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG
- case SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG:
-#endif
- case SIMPLE_ARRAY_SINGLE_FLOAT_WIDETAG:
- case SIMPLE_ARRAY_DOUBLE_FLOAT_WIDETAG:
-#ifdef SIMPLE_ARRAY_LONG_FLOAT_WIDETAG
- case SIMPLE_ARRAY_LONG_FLOAT_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_COMPLEX_SINGLE_FLOAT_WIDETAG
- case SIMPLE_ARRAY_COMPLEX_SINGLE_FLOAT_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_COMPLEX_DOUBLE_FLOAT_WIDETAG
- case SIMPLE_ARRAY_COMPLEX_DOUBLE_FLOAT_WIDETAG:
-#endif
-#ifdef SIMPLE_ARRAY_COMPLEX_LONG_FLOAT_WIDETAG
- case SIMPLE_ARRAY_COMPLEX_LONG_FLOAT_WIDETAG:
-#endif
- case SAP_WIDETAG:
- case WEAK_POINTER_WIDETAG:
-#ifdef LUTEX_WIDETAG
- case LUTEX_WIDETAG: