TreeList* TreeList::removeChunkReplaceIfNeeded(TreeChunk* tc) { TreeList* retTL = this; FreeChunk* list = head(); assert(!list || list != list->next(), "Chunk on list twice"); assert(tc != NULL, "Chunk being removed is NULL"); assert(parent() == NULL || this == parent()->left() || this == parent()->right(), "list is inconsistent"); assert(tc->isFree(), "Header is not marked correctly"); assert(head() == NULL || head()->prev() == NULL, "list invariant"); assert(tail() == NULL || tail()->next() == NULL, "list invariant"); FreeChunk* prevFC = tc->prev(); TreeChunk* nextTC = TreeChunk::as_TreeChunk(tc->next()); assert(list != NULL, "should have at least the target chunk"); // Is this the first item on the list? if (tc == list) { // The "getChunk..." functions for a TreeList will not return the // first chunk in the list unless it is the last chunk in the list // because the first chunk is also acting as the tree node. // When coalescing happens, however, the first chunk in the a tree // list can be the start of a free range. Free ranges are removed // from the free lists so that they are not available to be // allocated when the sweeper yields (giving up the free list lock) // to allow mutator activity. If this chunk is the first in the // list and is not the last in the list, do the work to copy the // TreeList from the first chunk to the next chunk and update all // the TreeList pointers in the chunks in the list. if (nextTC == NULL) { assert(prevFC == NULL, "Not last chunk in the list") set_tail(NULL); set_head(NULL); } else { debug_only( if (PrintGC && Verbose) { gclog_or_tty->print_cr("Removing first but not only chunk in TreeList"); gclog_or_tty->print_cr("Node: " INTPTR_FORMAT " parent: " INTPTR_FORMAT " right: " INTPTR_FORMAT " left: " INTPTR_FORMAT, tc, tc->list()->parent(), tc->list()->right(), tc->list()->left()); gclog_or_tty->print_cr("Next before: " INTPTR_FORMAT " parent: " INTPTR_FORMAT " right: " INTPTR_FORMAT " left: " INTPTR_FORMAT, nextTC, nextTC->list()->parent(), nextTC->list()->right(), nextTC->list()->left()); gclog_or_tty->print_cr(" head: " INTPTR_FORMAT " tail: " INTPTR_FORMAT, nextTC->list()->head(), nextTC->list()->tail()); } ) // copy embedded list. nextTC->set_embedded_list(tc->embedded_list()); retTL = nextTC->embedded_list(); // Fix the pointer to the list in each chunk in the list. // This can be slow for a long list. Consider having // an option that does not allow the first chunk on the // list to be coalesced. for (TreeChunk* curTC = nextTC; curTC != NULL; curTC = TreeChunk::as_TreeChunk(curTC->next())) { curTC->set_list(retTL); } // Fix the parent to point to the new TreeList. if (retTL->parent() != NULL) { if (this == retTL->parent()->left()) { retTL->parent()->setLeft(retTL); } else { assert(this == retTL->parent()->right(), "Parent is incorrect"); retTL->parent()->setRight(retTL); } } // Fix the children's parent pointers to point to the // new list. assert(right() == retTL->right(), "Should have been copied"); if (retTL->right() != NULL) { retTL->right()->setParent(retTL); } assert(left() == retTL->left(), "Should have been copied"); if (retTL->left() != NULL) { retTL->left()->setParent(retTL); } retTL->link_head(nextTC); debug_only( if (PrintGC && Verbose) { gclog_or_tty->print_cr("Next after: " INTPTR_FORMAT " parent: " INTPTR_FORMAT " right: " INTPTR_FORMAT " left: " INTPTR_FORMAT, nextTC, nextTC->list()->parent(), nextTC->list()->right(), nextTC->list()->left()); gclog_or_tty->print_cr(" head: " INTPTR_FORMAT " tail: " INTPTR_FORMAT, nextTC->list()->head(), nextTC->list()->tail()); } ) assert(nextTC->isFree(), "Should be a free chunk"); }