Index: src/mark_compact/mspace_alloc.cpp =================================================================== --- src/mark_compact/mspace_alloc.cpp (revision 465167) +++ src/mark_compact/mspace_alloc.cpp (working copy) @@ -1,89 +1,92 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -#include "mspace_collect.h" +/** + * @author Xiao-Feng Li, 2006/10/05 + */ -static Boolean mspace_alloc_block(Mspace* mspace, Alloc_Context* alloc_ctx) -{ - int old_free_idx = mspace->free_block_idx; - int new_free_idx = old_free_idx+1; - - Block_Info* curr_alloc_block = (Block_Info* )alloc_ctx->curr_alloc_block; - if(curr_alloc_block != NULL){ /* it is NULL at first time */ - assert(curr_alloc_block->status == BLOCK_IN_USE); - curr_alloc_block->status = BLOCK_USED; - curr_alloc_block->block->free = alloc_ctx->free; - } - - while( mspace_has_free_block(mspace)){ - - unsigned int allocated_idx = atomic_cas32(&mspace->free_block_idx, new_free_idx, old_free_idx); - - if(allocated_idx != (POINTER_SIZE_INT)old_free_idx){ - old_free_idx = mspace->free_block_idx; - new_free_idx = old_free_idx+1; - continue; - } - - Block_Info* curr_alloc_block = &(mspace->block_info[allocated_idx]); - - assert(curr_alloc_block->status == BLOCK_FREE); - curr_alloc_block->status = BLOCK_IN_USE; - mspace->num_used_blocks++; - - alloc_ctx->curr_alloc_block = curr_alloc_block; - Block_Header* block = curr_alloc_block->block; - memset(block->free, 0, (unsigned int)block->ceiling - (unsigned int)block->free); - alloc_ctx->free = block->free; - alloc_ctx->ceiling = block->ceiling; - - return TRUE; - } +#include "mspace.h" + +static Boolean mspace_alloc_block(Mspace* mspace, Allocator* allocator) +{ + Block_Header* alloc_block = (Block_Header* )allocator->alloc_block; + /* put back the used block */ + if(alloc_block != NULL){ /* it is NULL at first time */ + assert(alloc_block->status == BLOCK_IN_USE); + alloc_block->status = BLOCK_USED; + alloc_block->free = allocator->free; + } + + /* now try to get a new block */ + unsigned int old_free_idx = mspace->free_block_idx; + unsigned int new_free_idx = old_free_idx+1; + while( old_free_idx <= mspace->ceiling_block_idx ){ + unsigned int allocated_idx = atomic_cas32(&mspace->free_block_idx, new_free_idx, old_free_idx); + if(allocated_idx != old_free_idx){ + old_free_idx = mspace->free_block_idx; + new_free_idx = old_free_idx+1; + continue; + } + /* ok, got one */ + alloc_block = (Block_Header*)&(mspace->blocks[allocated_idx - mspace->first_block_idx]); + assert(alloc_block->status == BLOCK_FREE); + alloc_block->status = BLOCK_IN_USE; + mspace->num_used_blocks++; + memset(alloc_block->free, 0, GC_BLOCK_BODY_SIZE_BYTES); + + /* set allocation context */ + allocator->free = alloc_block->free; + allocator->ceiling = alloc_block->ceiling; + allocator->alloc_block = (Block*)alloc_block; + + return TRUE; + } + + /* if Mspace is used for mutator allocation, here a collection should be triggered. + else if this is only for collector allocation, when code goes here, it means + Mspace is not enough to hold Nursery live objects, so the invoker of this routine + should throw out-of-memory exception. + But because in our design, we don't do any Mspace allocation during collection, this + path should never be reached. That's why we assert(0) here. */ + assert(0); + return FALSE; - /* FIXME:: collect Mspace if for mutator, else assert(0) */ - assert(0); - return FALSE; - } - -struct GC_Gen; + +struct GC_Gen; Space* gc_get_mos(GC_Gen* gc); -void* mspace_alloc(unsigned int size, Alloc_Context* alloc_ctx) +void* mspace_alloc(unsigned int size, Allocator* allocator) { void *p_return = NULL; - - Mspace* mspace = (Mspace*)gc_get_mos((GC_Gen*)alloc_ctx->gc); + + Mspace* mspace = (Mspace*)gc_get_mos((GC_Gen*)allocator->gc); /* All chunks of data requested need to be multiples of GC_OBJECT_ALIGNMENT */ assert((size % GC_OBJECT_ALIGNMENT) == 0); assert( size <= GC_OBJ_SIZE_THRESHOLD ); - /* check if collector local alloc block is ok. If not, grab a new block */ - p_return = thread_local_alloc(size, alloc_ctx); + /* check if collector local alloc block is ok. If not, grab a new block */ + p_return = thread_local_alloc(size, allocator); if(p_return) return p_return; - /* grab a new block */ - Boolean ok = mspace_alloc_block(mspace, alloc_ctx); - assert(ok); - - p_return = thread_local_alloc(size, alloc_ctx); + /* grab a new block */ + Boolean ok = mspace_alloc_block(mspace, allocator); + assert(ok); + + p_return = thread_local_alloc(size, allocator); assert(p_return); return p_return; Index: src/mark_compact/mspace_collect.h =================================================================== --- src/mark_compact/mspace_collect.h (revision 465167) +++ src/mark_compact/mspace_collect.h (working copy) @@ -1,148 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#ifndef _MSC_COLLECT_H_ -#define _MSC_COLLECT_H_ - -#include "mspace.h" - -inline Block_Header* mspace_get_first_block_for_nos(Mspace* mspace, unsigned int* target_blk_idx) -{ - unsigned int index = mspace->free_block_idx; - *target_blk_idx = index; - return mspace->block_info[index].block; -} - -inline Block_Header* mspace_get_next_block_for_nos(Mspace* mspace, unsigned int* target_blk_idx) -{ - unsigned int index = *target_blk_idx; - - *target_blk_idx = ++index; - - if( index >= mspace->num_current_blocks) return NULL; - - return mspace->block_info[index].block; -} - -inline void block_clear_markbits(Block_Header* block) -{ - unsigned int* mark_table = block->mark_table; - memset(mark_table, 0, MARKBIT_TABLE_SIZE_WORDS*BYTES_PER_WORD); - return; -} - -inline Block_Header* mspace_get_first_compact_block(Mspace* mspace, unsigned int* compact_blk_idx) -{ - assert( mspace->block_info[0].status != BLOCK_FREE ); - - *compact_blk_idx = 0; - return mspace->block_info[0].block; -} - -inline Block_Header* mspace_get_next_compact_block(Mspace* mspace, unsigned int* compact_blk_idx) -{ - unsigned int index = *compact_blk_idx; - - if( ++index == mspace->num_used_blocks ) return NULL; - - *compact_blk_idx = index; - assert( mspace->block_info[index].status != BLOCK_FREE ); - - return mspace->block_info[index].block; -} - -inline Block_Header* mspace_get_first_target_block(Mspace* mspace, unsigned int* target_blk_idx) -{ - assert( mspace->block_info[0].status != BLOCK_FREE); - - *target_blk_idx = 0; - return mspace->block_info[0].block; -} - -inline Block_Header* mspace_get_next_target_block(Mspace* mspace, unsigned int* target_blk_idx) -{ - unsigned int index = *target_blk_idx; - - *target_blk_idx = ++index; - /* trick! free_block_idx is changed after computing target addresses */ - assert( mspace->block_info[index].status != BLOCK_FREE && (index < mspace->free_block_idx)); - - return mspace->block_info[index].block; - -} - -inline Partial_Reveal_Object* block_get_first_marked_object(Block_Header* block, unsigned int* mark_bit_idx) -{ - unsigned int* mark_table = block->mark_table; - unsigned int* table_end = mark_table + MARKBIT_TABLE_SIZE_WORDS; - - unsigned j=0; - unsigned int k=0; - while( (mark_table + j) < table_end){ - unsigned int markbits = *(mark_table+j); - if(!markbits){ j++; continue; } - while(k<32){ - if( !(markbits& (1<mark_table; - unsigned int* table_end = mark_table + MARKBIT_TABLE_SIZE_WORDS; - unsigned int bit_index = *mark_bit_idx; - - unsigned int j = bit_index >> BIT_SHIFT_TO_BITS_PER_WORD; - unsigned int k = (bit_index & BIT_MASK_TO_BITS_PER_WORD) + 1; - - while( (mark_table + j) < table_end){ - unsigned int markbits = *(mark_table+j); - if(!markbits){ j++; continue; } - while(k<32){ - if( !(markbits& (1<blocks; } + +static Block_Header* mspace_get_next_compact_block(Mspace* mspace, Block_Header* block) +{ return block->next; } + +static Block_Header* mspace_get_first_target_block(Mspace* mspace) +{ return (Block_Header*)mspace->blocks; } + +static Block_Header* mspace_get_next_target_block(Mspace* mspace, Block_Header* block) +{ return block->next; } + +void mspace_save_reloc(Mspace* mspace, Partial_Reveal_Object** p_ref) +{ + Block_Header* block = GC_BLOCK_HEADER(p_ref); + block->reloc_table->push_back(p_ref); + return; +} + +void mspace_update_reloc(Mspace* mspace) +{ + SlotVector* reloc_table; + /* update refs in mspace */ + Block* blocks = mspace->blocks; + for(unsigned int i=0; i < mspace->num_used_blocks; i++){ + Block_Header* block = (Block_Header*)&(blocks[i]); + reloc_table = block->reloc_table; + for(unsigned int j=0; j < reloc_table->size(); j++){ + Partial_Reveal_Object** p_ref = (*reloc_table)[j]; + Partial_Reveal_Object* p_target_obj = get_forwarding_pointer_in_obj_info(*p_ref); + *p_ref = p_target_obj; + } + reloc_table->clear(); + } + + return; +} + +Boolean mspace_mark_object(Mspace* mspace, Partial_Reveal_Object *p_obj) +{ + obj_mark_in_vt(p_obj); + + unsigned int obj_word_index = OBJECT_WORD_INDEX_TO_MARKBIT_TABLE(p_obj); + unsigned int obj_offset_in_word = OBJECT_WORD_OFFSET_IN_MARKBIT_TABLE(p_obj); + + unsigned int *p_word = &(GC_BLOCK_HEADER(p_obj)->mark_table[obj_word_index]); + unsigned int word_mask = (1<mark_table[obj_word_index]); + unsigned int word_mask = (1< (unsigned int)GC_BLOCK_END(dest_block)){ + dest_block->free = dest_addr; + dest_block = mspace_get_next_target_block(mspace, dest_block); + dest_addr = GC_BLOCK_BODY(dest_block); + } + assert(((unsigned int)dest_addr + obj_size) <= (unsigned int)GC_BLOCK_END(dest_block)); + + Obj_Info_Type obj_info = get_obj_info(p_obj); + if( obj_info != 0 ) { + mspace->obj_info_map->insert(ObjectMap::value_type((Partial_Reveal_Object*)dest_addr, obj_info)); + } + + assert( (unsigned int) p_obj >= (unsigned int)dest_addr ); + set_forwarding_pointer_in_obj_info(p_obj, dest_addr); + + /* FIXME: should use alloc to handle alignment requirement */ + dest_addr = (void *) WORD_SIZE_ROUND_UP((unsigned int) dest_addr + obj_size); + p_obj = block_get_next_marked_object(curr_block, &mark_bit_idx); + + } + curr_block = mspace_get_next_compact_block(mspace, curr_block); + } + + + mspace->free_block_idx = dest_block->block_idx+1; + + /* fail to evacuate any room, FIXME:: do nothing at the moment */ + if( mspace->free_block_idx == mspace->first_block_idx + mspace->num_used_blocks) + return FALSE; + + return TRUE; +} + +static void mspace_restore_obj_info(Mspace* mspace) +{ + ObjectMap* objmap = mspace->obj_info_map; + ObjectMap::iterator obj_iter; + for( obj_iter=objmap->begin(); obj_iter!=objmap->end(); obj_iter++){ + Partial_Reveal_Object* p_target_obj = obj_iter->first; + Obj_Info_Type obj_info = obj_iter->second; + set_obj_info(p_target_obj, obj_info); + } + objmap->clear(); + return; +} + +static void reset_mspace_after_compaction(Mspace* mspace) +{ + unsigned int old_num_used = mspace->num_used_blocks; + unsigned int new_num_used = mspace->free_block_idx - mspace->first_block_idx; + unsigned int num_used = old_num_used>new_num_used? old_num_used:new_num_used; + + Block* blocks = mspace->blocks; + for(unsigned int i=0; i < num_used; i++){ + Block_Header* block = (Block_Header*)&(blocks[i]); + block_clear_mark_table(block); + block->status = BLOCK_USED; + + if(i >= new_num_used){ + block->status = BLOCK_FREE; + block->free = GC_BLOCK_BODY(block); + } + } + mspace->num_used_blocks = new_num_used; +} + +#include "../verify/verify_live_heap.h" + +static void mspace_sliding_compact(Collector* collector, Mspace* mspace) +{ + Block_Header* curr_block = mspace_get_first_compact_block(mspace); + + while( curr_block ){ + unsigned int mark_bit_idx; + Partial_Reveal_Object* p_obj = block_get_first_marked_object(curr_block, &mark_bit_idx); + + while( p_obj ){ + assert( obj_is_marked_in_vt(p_obj)); + obj_unmark_in_vt(p_obj); + + unsigned int obj_size = vm_object_size(p_obj); + Partial_Reveal_Object *p_target_obj = get_forwarding_pointer_in_obj_info(p_obj); + if( p_obj != p_target_obj){ + memmove(p_target_obj, p_obj, obj_size); + + if (verify_live_heap) + /* we forwarded it, we need remember it for verification */ + event_collector_move_obj(p_obj, p_target_obj, collector); + } + + set_obj_info(p_target_obj, 0); + + p_obj = block_get_next_marked_object(curr_block, &mark_bit_idx); + } + + curr_block = mspace_get_next_compact_block(mspace, curr_block); + } + + mspace_restore_obj_info(mspace); + reset_mspace_after_compaction(mspace); + + return; +} + +void gc_gen_update_repointed_refs(Collector* collector); + +static void mark_compact_mspace(Collector* collector) +{ + GC_Gen* gc = (GC_Gen*)collector->gc; + Mspace* mspace = (Mspace*)gc_get_mos(gc); + Fspace* fspace = (Fspace*)gc_get_nos(gc); + + /* FIXME:: Single-threaded mark-compaction for mspace currently */ + + /* Pass 1: mark all live objects in heap, and save all the slots that + have references that are going to be repointed */ + mark_scan_heap(collector); + + /* Pass 2: assign target addresses for all to-be-moved objects */ + Boolean ok; + ok = mspace_compute_object_target(mspace); + assert(ok); /* free at least one block */ + ok = fspace_compute_object_target(collector, fspace); + assert(ok); /* FIXME:: throw out-of-memory exception if not ok */ + + /* Pass 3: update all references whose objects are to be moved */ + gc_gen_update_repointed_refs(collector); + + /* Pass 4: do the compaction and reset blocks */ + mspace_sliding_compact(collector, mspace); + fspace_copy_collect(collector, fspace); + + return; +} + +void mspace_collection(Mspace* mspace) +{ + mspace->num_collections++; + + GC* gc = mspace->gc; + + collector_execute_task(gc, (TaskType)mark_compact_mspace, (Space*)mspace); + + return; +} Index: src/mark_compact/mspace.cpp =================================================================== --- src/mark_compact/mspace.cpp (revision 465167) +++ src/mark_compact/mspace.cpp (working copy) @@ -1,91 +1,141 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#include "mspace.h" - -static void mspace_init_blocks(Mspace* mspace) -{ - int size = sizeof(Block_Info)* mspace->num_total_blocks; - Block_Info* block_info = (Block_Info*)STD_MALLOC(size); - memset(block_info, 0, size); - - for(unsigned int i=0; i < mspace->num_current_blocks; i++){ - Block_Header* block = (Block_Header*)((unsigned int)space_heap_start((Space*)mspace) + i*mspace->block_size_bytes); - block->free = (void*)((unsigned int)block + GC_BLOCK_HEADER_SIZE_BYTES); - block->ceiling = (void*)((unsigned int)block + mspace->block_size_bytes); - block->base = block->free; - block->block_idx = i; - - block_info[i].block = block; - block_info[i].status = BLOCK_FREE; - block_info[i].reloc_table = new SlotVector(); - } - - mspace->block_info = block_info; - - return; -} - -struct GC_Gen; -extern void gc_set_mos(GC_Gen* gc, Space* space); -void mspace_initialize(GC* gc, void* start, unsigned int mspace_size) -{ - Mspace* mspace = (Mspace*)STD_MALLOC( sizeof(Mspace)); - assert(mspace); - memset(mspace, 0, sizeof(Mspace)); - - mspace->block_size_bytes = GC_BLOCK_SIZE_BYTES; - mspace->reserved_heap_size = mspace_size; - mspace->num_total_blocks = mspace_size/mspace->block_size_bytes; - - mspace_size >>= 1; - void* reserved_base = start; - int status = port_vmem_commit(&reserved_base, mspace_size, gc->allocated_memory); - assert(status == APR_SUCCESS && reserved_base == start); - - memset(reserved_base, 0, mspace_size); - mspace->committed_heap_size = mspace_size; - mspace->heap_start = reserved_base; - mspace->heap_end = (void *)((unsigned int)reserved_base + mspace->reserved_heap_size); - mspace->num_current_blocks = mspace_size/mspace->block_size_bytes; - - mspace->num_used_blocks = 0; - mspace->free_block_idx = 0; - - mspace_init_blocks(mspace); - - mspace->obj_info_map = new ObjectMap(); - mspace->mark_object_func = mspace_mark_object; - mspace->save_reloc_func = mspace_save_reloc; - mspace->update_reloc_func = mspace_update_reloc; - - mspace->move_object = TRUE; - mspace->gc = gc; - gc_set_mos((GC_Gen*)gc, (Space*)mspace); - - return; -} - - -void mspace_destruct(Mspace* mspace) -{ - /* inverse of initialize */ -} - +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#include "mspace.h" + +static void mspace_destruct_blocks(Mspace* mspace) +{ + Block* blocks = (Block*)mspace->blocks; + for(unsigned int i=0; i < mspace->num_managed_blocks; i++){ + Block_Header* block = (Block_Header*)&(blocks[i]); + delete block->reloc_table; + block->reloc_table = NULL; + } + + return; +} + +static void mspace_init_blocks(Mspace* mspace) +{ + Block* blocks = (Block*)mspace->heap_start; + Block_Header* last_block = (Block_Header*)blocks; + unsigned int start_idx = mspace->first_block_idx; + for(unsigned int i=0; i < mspace->num_managed_blocks; i++){ + Block_Header* block = (Block_Header*)&(blocks[i]); + block->free = (void*)((unsigned int)block + GC_BLOCK_HEADER_SIZE_BYTES); + block->ceiling = (void*)((unsigned int)block + GC_BLOCK_SIZE_BYTES); + block->base = block->free; + block->block_idx = i + start_idx; + block->status = BLOCK_FREE; + block->reloc_table = new SlotVector(); + last_block->next = block; + last_block = block; + } + last_block->next = NULL; + mspace->blocks = blocks; + + return; +} + +struct GC_Gen; +extern void gc_set_mos(GC_Gen* gc, Space* space); +void mspace_initialize(GC* gc, void* start, unsigned int mspace_size) +{ + Mspace* mspace = (Mspace*)STD_MALLOC( sizeof(Mspace)); + assert(mspace); + memset(mspace, 0, sizeof(Mspace)); + + mspace->reserved_heap_size = mspace_size; + mspace->num_total_blocks = mspace_size >> GC_BLOCK_SHIFT_COUNT; + + void* reserved_base = start; + int status = port_vmem_commit(&reserved_base, mspace_size, gc->allocated_memory); + assert(status == APR_SUCCESS && reserved_base == start); + + memset(reserved_base, 0, mspace_size); + mspace->committed_heap_size = mspace_size; + mspace->heap_start = reserved_base; + mspace->heap_end = (void *)((unsigned int)reserved_base + mspace->reserved_heap_size); + mspace->num_managed_blocks = mspace_size >> GC_BLOCK_SHIFT_COUNT; + + mspace->first_block_idx = GC_BLOCK_INDEX_FROM(gc->heap_start, reserved_base); + mspace->ceiling_block_idx = mspace->first_block_idx + mspace->num_managed_blocks - 1; + + mspace->num_used_blocks = 0; + mspace->free_block_idx = mspace->first_block_idx; + + mspace_init_blocks(mspace); + + mspace->obj_info_map = new ObjectMap(); + mspace->mark_object_func = mspace_mark_object; + mspace->save_reloc_func = mspace_save_reloc; + mspace->update_reloc_func = mspace_update_reloc; + + mspace->move_object = TRUE; + mspace->gc = gc; + gc_set_mos((GC_Gen*)gc, (Space*)mspace); + + return; +} + + +void mspace_destruct(Mspace* mspace) +{ + //FIXME:: when map the to-half, the decommission start address should change + mspace_destruct_blocks(mspace); + port_vmem_decommit(mspace->heap_start, mspace->committed_heap_size, mspace->gc->allocated_memory); + STD_FREE(mspace); +} + + /* for non-gen MINOR_COLLECTION, mspace has both obj and marktable to be cleared, + because the marking phase will mark them, but then never touch them + + FIXME:: the marking choice between header and mark table has to be decided. + Obj header marking has advantage of idempotent, while table marking can prefetch + If we choose only one, we will not have the two version clearings: one after + MAJOR_COLLECTION, one after non-gen MINOR_COLLECTION */ + +void reset_mspace_after_copy_nursery(Mspace* mspace) +{ + /* for major collection we do nothing, the reset is done there */ + assert( mspace->gc->collect_kind == MINOR_COLLECTION ); + + unsigned int new_num_used = mspace->free_block_idx - mspace->first_block_idx; + unsigned int old_num_used = mspace->num_used_blocks; + + /* At the moment, for MINOR_COLLECTION, only non-gen collection does copying. + The generational version does forwarding */ + assert( !gc_requires_barriers()); + + Block* blocks = mspace->blocks; + for(unsigned int i=0; i < old_num_used; i++){ + Block_Header* block = (Block_Header*)&(blocks[i]); + block_clear_markbits(block); + } + + for(unsigned int i=old_num_used; i < new_num_used; i++){ + Block_Header* block = (Block_Header*)&(blocks[i]); + block->status = BLOCK_USED; + } + + mspace->num_used_blocks = new_num_used; + return; +} + Index: src/mark_compact/mspace.h =================================================================== --- src/mark_compact/mspace.h (revision 465167) +++ src/mark_compact/mspace.h (working copy) @@ -1,125 +1,75 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#ifndef _MSC_SPACE_H_ -#define _MSC_SPACE_H_ - -#include "../common/gc_common.h" -#include "../thread/thread_alloc.h" - -typedef struct Block_Header { - void* base; - void* free; - void* ceiling; - unsigned int block_idx; - unsigned int mark_table[1]; /* entry num == MARKBIT_TABLE_SIZE_WORDS */ -}Block_Header; - -enum Block_Status { - BLOCK_NIL, - BLOCK_FREE, - BLOCK_IN_USE, - BLOCK_USED -}; - -typedef struct Block_Info{ - Block_Header* block; - Boolean status; - - SlotVector* reloc_table; - -}Block_Info; - -/* Mark-compaction space is orgnized into blocks*/ -typedef struct Mspace{ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#ifndef _MSC_SPACE_H_ +#define _MSC_SPACE_H_ + +#include "../common/gc_block.h" +#include "../thread/thread_alloc.h" + +/* Mark-compaction space is orgnized into blocks*/ +typedef struct Mspace{ /* <-- first couple of fields are overloadded as Space */ void* heap_start; void* heap_end; unsigned int reserved_heap_size; unsigned int committed_heap_size; - unsigned int num_collections; - GC* gc; - Boolean move_object; + unsigned int num_collections; + GC* gc; + Boolean move_object; Boolean (*mark_object_func)(Mspace* space, Partial_Reveal_Object* p_obj); void (*save_reloc_func)(Mspace* space, Partial_Reveal_Object** p_ref); - void (*update_reloc_func)(Mspace* space); - /* END of Space --> */ - - Block_Info* block_info; /* data structure for all the blocks */ - - volatile unsigned int num_used_blocks; - volatile unsigned int free_block_idx; - unsigned int compact_block_low_idx; - unsigned int compact_block_high_idx; - - unsigned int block_size_bytes; - unsigned int num_current_blocks; - unsigned int num_total_blocks; - - /* during compaction, save non-zero obj_info who's overwritten by forwarding pointer */ - ObjectMap* obj_info_map; - -}Mspace; - -void mspace_initialize(GC* gc, void* reserved_base, unsigned int mspace_size); -void mspace_destruct(Mspace* mspace); - -inline unsigned int mspace_free_memory_size(Mspace* mspace){ return GC_BLOCK_SIZE_BYTES * (mspace->num_current_blocks - mspace->num_used_blocks); } -inline Boolean mspace_has_free_block(Mspace* mspace){ return mspace->free_block_idx < mspace->num_current_blocks; } - -void* mspace_alloc(unsigned size, Alloc_Context *alloc_ctx); -void mspace_collection(Mspace* mspace); - -#define GC_BLOCK_HEADER_VARS_SIZE_BYTES (unsigned int)&(((Block_Header*)0)->mark_table) - -/* BlockSize - MarkbitTable*32 = HeaderVars + MarkbitTable - => MarkbitTable = (BlockSize - HeaderVars)/33 */ -#define MARKBIT_TABLE_COMPUTE_DIVISOR 33 -/* +1 to round up*/ -#define MARKBIT_TABLE_COMPUTED_SIZE_BYTE ((GC_BLOCK_SIZE_BYTES-GC_BLOCK_HEADER_VARS_SIZE_BYTES)/MARKBIT_TABLE_COMPUTE_DIVISOR + 1) -#define MARKBIT_TABLE_SIZE_WORDS ((MARKBIT_TABLE_COMPUTED_SIZE_BYTE + MASK_OF_BYTES_PER_WORD)&~MASK_OF_BYTES_PER_WORD) -#define MARKBIT_TABLE_SIZE_BYTES (MARKBIT_TABLE_SIZE_WORDS * BYTES_PER_WORD) - -#define GC_BLOCK_HEADER_SIZE_BYTES (MARKBIT_TABLE_SIZE_BYTES + GC_BLOCK_HEADER_VARS_SIZE_BYTES) -#define GC_BLOCK_BODY_SIZE_BYTES (GC_BLOCK_SIZE_BYTES - GC_BLOCK_HEADER_SIZE_BYTES) -#define GC_BLOCK_BODY(block) ((void*)((unsigned int)block + GC_BLOCK_HEADER_SIZE_BYTES)) -#define GC_BLOCK_END(block) ((void*)((unsigned int)block + GC_BLOCK_SIZE_BYTES)) - -#define GC_BLOCK_LOW_MASK ((unsigned int)(GC_BLOCK_SIZE_BYTES - 1)) -#define GC_BLOCK_HIGH_MASK (~GC_BLOCK_LOW_MASK) -#define GC_BLOCK_HEADER(addr) ((Block_Header *)((unsigned int)addr & GC_BLOCK_HIGH_MASK)) -#define GC_BLOCK_INDEX(addr) ((unsigned int)(GC_BLOCK_HEADER(addr)->block_idx)) -#define GC_BLOCK_INFO_ADDRESS(mspace, addr) ((Block_Info *)&(mspace->block_info[GC_BLOCK_INDEX(addr)])) -#define GC_BLOCK_INFO_BLOCK(mspace, block) ((Block_Info *)&(mspace->block_info[block->block_idx])) - -#define ADDRESS_OFFSET_TO_BLOCK_HEADER(addr) ((unsigned int)((unsigned int)addr&GC_BLOCK_LOW_MASK)) -#define ADDRESS_OFFSET_IN_BLOCK_BODY(addr) ((unsigned int)(ADDRESS_OFFSET_TO_BLOCK_HEADER(addr)- GC_BLOCK_HEADER_SIZE_BYTES)) - -#define OBJECT_BIT_INDEX_TO_MARKBIT_TABLE(p_obj) (ADDRESS_OFFSET_IN_BLOCK_BODY(p_obj) >> 2) -#define OBJECT_WORD_INDEX_TO_MARKBIT_TABLE(p_obj) (OBJECT_BIT_INDEX_TO_MARKBIT_TABLE(p_obj) >> BIT_SHIFT_TO_BITS_PER_WORD) -#define OBJECT_WORD_OFFSET_IN_MARKBIT_TABLE(p_obj) (OBJECT_BIT_INDEX_TO_MARKBIT_TABLE(p_obj) & BIT_MASK_TO_BITS_PER_WORD) - -#define GC_BLOCK_OBJECT_AT_INDEX(block, idx) (block->mark_table[idx]) - -Boolean mspace_mark_object(Mspace* mspace, Partial_Reveal_Object *p_obj); + void (*update_reloc_func)(Mspace* space); + /* END of Space --> */ + + Block* blocks; /* short-cut for mpsace blockheader access, not mandatory */ + + /* FIXME:: the block indices should be replaced with block header addresses */ + unsigned int first_block_idx; + unsigned int ceiling_block_idx; + volatile unsigned int free_block_idx; + + unsigned int num_used_blocks; + unsigned int num_managed_blocks; + unsigned int num_total_blocks; + + /* during compaction, save non-zero obj_info who's overwritten by forwarding pointer */ + ObjectMap* obj_info_map; + +}Mspace; + +void mspace_initialize(GC* gc, void* reserved_base, unsigned int mspace_size); +void mspace_destruct(Mspace* mspace); + +inline Boolean mspace_has_free_block(Mspace* mspace){ return mspace->free_block_idx <= mspace->ceiling_block_idx; } +inline unsigned int mspace_free_memory_size(Mspace* mspace){ return GC_BLOCK_SIZE_BYTES * (mspace->ceiling_block_idx - mspace->free_block_idx + 1); } +inline Boolean mspace_used_memory_size(Mspace* mspace){ return GC_BLOCK_SIZE_BYTES * mspace->num_used_blocks; } + +void* mspace_alloc(unsigned size, Allocator *allocator); +void mspace_collection(Mspace* mspace); + +void reset_mspace_after_copy_nursery(Mspace* mspace); + + +Boolean mspace_mark_object(Mspace* mspace, Partial_Reveal_Object *p_obj); void mspace_save_reloc(Mspace* mspace, Partial_Reveal_Object** p_ref); -void mspace_update_reloc(Mspace* mspace); - -#endif //#ifdef _MSC_SPACE_H_ \ No newline at end of file +void mspace_update_reloc(Mspace* mspace); + +#endif //#ifdef _MSC_SPACE_H_ Index: src/mark_compact/mspace_collect.cpp =================================================================== --- src/mark_compact/mspace_collect.cpp (revision 465167) +++ src/mark_compact/mspace_collect.cpp (working copy) @@ -1,334 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#include "mspace_collect.h" -#include "../thread/collector.h" -#include "../trace_forward/fspace.h" -#include "../common/interior_pointer.h" -struct GC_Gen; -Space* gc_get_nos(GC_Gen* gc); -Space* gc_get_mos(GC_Gen* gc); -Space* gc_get_los(GC_Gen* gc); - -void mspace_save_reloc(Mspace* mspace, Partial_Reveal_Object** p_ref) -{ - Block_Info* block_info = GC_BLOCK_INFO_ADDRESS(mspace, p_ref); - block_info->reloc_table->push_back(p_ref); - return; -} - -void mspace_update_reloc(Mspace* mspace) -{ - SlotVector* reloc_table; - /* update refs in mspace */ - for(unsigned int i=0; i < mspace->num_used_blocks; i++){ - Block_Info* block_info = &(mspace->block_info[i]); - reloc_table = block_info->reloc_table; - for(unsigned int j=0; j < reloc_table->size(); j++){ - Partial_Reveal_Object** p_ref = (*reloc_table)[j]; - Partial_Reveal_Object* p_target_obj = get_forwarding_pointer_in_obj_info(*p_ref); - *p_ref = p_target_obj; - } - reloc_table->clear(); - } - - return; -} - -Boolean mspace_mark_object(Mspace* mspace, Partial_Reveal_Object *p_obj) -{ - obj_mark_in_vt(p_obj); - - unsigned int obj_word_index = OBJECT_WORD_INDEX_TO_MARKBIT_TABLE(p_obj); - unsigned int obj_offset_in_word = OBJECT_WORD_OFFSET_IN_MARKBIT_TABLE(p_obj); - - unsigned int *p_word = &(GC_BLOCK_HEADER(p_obj)->mark_table[obj_word_index]); - unsigned int word_mask = (1<mark_table[obj_word_index]); - unsigned int word_mask = (1< (unsigned int)GC_BLOCK_END(dest_block)){ - dest_block->free = dest_addr; - dest_block = mspace_get_next_target_block(mspace, &target_blk_idx); - dest_addr = GC_BLOCK_BODY(dest_block); - } - assert(((unsigned int)dest_addr + obj_size) <= (unsigned int)GC_BLOCK_END(dest_block)); - - Obj_Info_Type obj_info = get_obj_info(p_obj); - if( obj_info != 0 ) { - mspace->obj_info_map->insert(ObjectMap::value_type((Partial_Reveal_Object*)dest_addr, obj_info)); - } - - //FIXME: should use alloc to handle alignment requirement - set_forwarding_pointer_in_obj_info(p_obj, dest_addr); - - dest_addr = (void *) WORD_SIZE_ROUND_UP((unsigned int) dest_addr + obj_size); - p_obj = block_get_next_marked_object(curr_block, &mark_bit_idx); - - } - curr_block = mspace_get_next_compact_block(mspace, &compact_blk_idx); - } - - - mspace->free_block_idx = dest_block->block_idx+1; - - /* fail to evacuate any room, FIXME:: do nothing at the moment */ - if( mspace->free_block_idx == mspace->num_current_blocks) - return FALSE; - - return TRUE; -} - -static Boolean fspace_compute_object_target(Collector* collector, Fspace* fspace) -{ - Mspace* mspace = (Mspace*)collector->collect_space; - unsigned int target_blk_idx; - Block_Header* dest_block = mspace_get_first_block_for_nos(mspace, &target_blk_idx); - void* dest_addr = GC_BLOCK_BODY(dest_block); - - unsigned int* mark_table = fspace->mark_table; - unsigned int* table_end = (unsigned int*)((POINTER_SIZE_INT)mark_table + fspace->mark_table_size); - unsigned int* fspace_start = (unsigned int*)fspace->heap_start; - Partial_Reveal_Object* p_obj = NULL; - - unsigned j=0; - while( (mark_table + j) < table_end){ - unsigned int markbits = *(mark_table+j); - if(!markbits){ j++; continue; } - unsigned int k=0; - while(k<32){ - if( !(markbits& (1< (unsigned int)GC_BLOCK_END(dest_block)){ - dest_block->free = dest_addr; - dest_block = mspace_get_next_block_for_nos(mspace, &target_blk_idx); - - if(dest_block == NULL) return FALSE; - dest_addr = GC_BLOCK_BODY(dest_block); - } - assert(((unsigned int)dest_addr + obj_size) <= (unsigned int)GC_BLOCK_END(dest_block)); - - Obj_Info_Type obj_info = get_obj_info(p_obj); - if( obj_info != 0 ) { - fspace->obj_info_map->insert(ObjectMap::value_type((Partial_Reveal_Object*)dest_addr, obj_info)); - } - - //FIXME: should use alloc to handle alignment requirement - set_forwarding_pointer_in_obj_info(p_obj, dest_addr); - - dest_addr = (void *) WORD_SIZE_ROUND_UP((unsigned int) dest_addr + obj_size); - - k++; - } - j++;; - } - - mspace->free_block_idx = dest_block->block_idx+1; - - return TRUE; -} - -static void update_relocated_refs(Collector* collector) -{ - GC_Gen* gc = (GC_Gen*)collector->gc; - Space* space; - space = gc_get_nos(gc); space->update_reloc_func(space); - space = gc_get_mos(gc); space->update_reloc_func(space); - space = gc_get_los(gc); space->update_reloc_func(space); - - gc_update_rootset((GC*)gc); - - space_update_remsets((Fspace*)gc_get_nos(gc)); - - /* FIXME:: interior table */ - update_rootset_interior_pointer(); - return; -} - -static void mspace_restore_obj_info(Mspace* mspace) -{ - ObjectMap* objmap = mspace->obj_info_map; - ObjectMap::iterator obj_iter; - for( obj_iter=objmap->begin(); obj_iter!=objmap->end(); obj_iter++){ - Partial_Reveal_Object* p_target_obj = obj_iter->first; - Obj_Info_Type obj_info = obj_iter->second; - set_obj_info(p_target_obj, obj_info); - } - objmap->clear(); - return; -} - -static void restore_saved_obj_info(Collector* collector) -{ - GC_Gen* gc = (GC_Gen*)collector->gc; - Space* space; - space = gc_get_nos(gc); fspace_restore_obj_info((Fspace*)space); - space = gc_get_mos(gc); mspace_restore_obj_info((Mspace*)space); - - return; -} - -static void reset_mspace_for_allocation(Mspace* mspace) -{ - unsigned int num_used = mspace->num_used_blocks; - unsigned int num_free = mspace->free_block_idx; - unsigned int index = num_used>num_free? num_used:num_free; - - for(unsigned int i=0; i < index; i++){ - Block_Info* block_info = &(mspace->block_info[i]); - block_clear_markbits(block_info->block); /* only needed for istatus = BLOCK_USED; - - if(i >= mspace->free_block_idx){ - block_info->status = BLOCK_FREE; - block_info->block->free = GC_BLOCK_BODY(block_info->block); - } - } - mspace->num_used_blocks = mspace->free_block_idx; -} - -#include "../verify/verify_live_heap.h" - -static void mspace_sliding_compact(Collector* collector, Mspace* mspace) -{ - unsigned int compact_blk_idx; - Block_Header* curr_block = mspace_get_first_compact_block(mspace, &compact_blk_idx); - - while( curr_block ){ - unsigned int mark_bit_idx; - Partial_Reveal_Object* p_obj = block_get_first_marked_object(curr_block, &mark_bit_idx); - - while( p_obj ){ - assert( obj_is_marked_in_vt(p_obj)); - obj_unmark_in_vt(p_obj); - - unsigned int obj_size = vm_object_size(p_obj); - Partial_Reveal_Object *p_target_obj = get_forwarding_pointer_in_obj_info(p_obj); - if( p_obj != p_target_obj){ - memmove(p_target_obj, p_obj, obj_size); - - if (verify_live_heap) - /* we forwarded it, we need remember it for verification */ - event_collector_move_obj(p_obj, p_target_obj, collector); - } - - set_obj_info(p_target_obj, 0); - - p_obj = block_get_next_marked_object(curr_block, &mark_bit_idx); - } - - curr_block = mspace_get_next_compact_block(mspace, &compact_blk_idx); - } - - reset_mspace_for_allocation(mspace); - - return; -} - -static void mark_compact_mspace(Collector* collector) -{ - /* Pass 1: mark all live objects in heap, and save all the outgoing pointers */ - mark_scan_heap(collector); - - /* Pass 2: assign target addresses for all to-be-moved objects */ - Boolean ok; - ok = mspace_compute_object_target((Mspace*)gc_get_mos((GC_Gen*)collector->gc)); - assert(ok); /* free at least one block */ - - ok = fspace_compute_object_target(collector, (Fspace*)gc_get_nos((GC_Gen*)collector->gc)); - assert(ok); /* FIXME:: throw out-of-memory exception if not ok */ - - /* Pass 3: update all references whose objects are to be moved */ - update_relocated_refs(collector); - - /* Pass 4: do the compaction and reset blocks */ - mspace_sliding_compact(collector, (Mspace*)collector->collect_space); - GC_Gen* gc = (GC_Gen*)collector->gc; - fspace_copy_collect(collector, (Fspace*)gc_get_nos(gc)); - - restore_saved_obj_info(collector); - - return; -} - -void mspace_collection(Mspace* mspace) -{ - mspace->num_collections++; - - GC* gc = mspace->gc; - - collector_execute_task(gc, (TaskType)mark_compact_mspace, (Space*)mspace); - - return; -} Index: src/trace_forward/fspace_collect_copy.cpp =================================================================== --- src/trace_forward/fspace_collect_copy.cpp (revision 0) +++ src/trace_forward/fspace_collect_copy.cpp (revision 0) @@ -0,0 +1,154 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#include "fspace.h" +#include "../mark_compact/mspace.h" +#include "../mark_sweep/lspace.h" +#include "../thread/collector.h" + +/* copying of fspace is only for MAJOR_COLLECTION or non-generational partial copy collection */ +static Block_Header* mspace_get_first_target_block_for_nos(Mspace* mspace) +{ + return (Block_Header*)&mspace->blocks[mspace->free_block_idx-mspace->first_block_idx]; +} + +static Block_Header* mspace_get_next_target_block_for_nos(Mspace* mspace, Block_Header* block) +{ return block->next; } + +static void fspace_restore_obj_info(Fspace* fspace) +{ + ObjectMap* objmap = fspace->obj_info_map; + ObjectMap::iterator obj_iter; + for( obj_iter=objmap->begin(); obj_iter!=objmap->end(); obj_iter++){ + Partial_Reveal_Object* p_target_obj = obj_iter->first; + Obj_Info_Type obj_info = obj_iter->second; + set_obj_info(p_target_obj, obj_info); + } + objmap->clear(); + return; +} + +struct GC_Gen; +Space* gc_get_mos(GC_Gen* gc); + +Boolean fspace_compute_object_target(Collector* collector, Fspace* fspace) +{ + Mspace* mspace = (Mspace*)gc_get_mos((GC_Gen*)collector->gc); + Block_Header* dest_block = mspace_get_first_target_block_for_nos(mspace); + Block_Header* curr_block = fspace_get_first_copy_block(fspace); + + void* dest_addr = GC_BLOCK_BODY(dest_block); + + while( curr_block ){ + unsigned int mark_bit_idx; + Partial_Reveal_Object* p_obj = block_get_first_marked_object(curr_block, &mark_bit_idx); + + while( p_obj ){ + assert( obj_is_marked_in_vt(p_obj)); + + unsigned int obj_size = vm_object_size(p_obj); + + if( ((unsigned int)dest_addr + obj_size) > (unsigned int)GC_BLOCK_END(dest_block)){ + dest_block->free = dest_addr; + dest_block = mspace_get_next_target_block_for_nos(mspace, dest_block); + if(dest_block == NULL) return FALSE; + dest_addr = GC_BLOCK_BODY(dest_block); + } + assert(((unsigned int)dest_addr + obj_size) <= (unsigned int)GC_BLOCK_END(dest_block)); + + Obj_Info_Type obj_info = get_obj_info(p_obj); + if( obj_info != 0 ) { + fspace->obj_info_map->insert(ObjectMap::value_type((Partial_Reveal_Object*)dest_addr, obj_info)); + } + set_forwarding_pointer_in_obj_info(p_obj, dest_addr); + + /* FIXME: should use alloc to handle alignment requirement */ + dest_addr = (void *) WORD_SIZE_ROUND_UP((unsigned int) dest_addr + obj_size); + p_obj = block_get_next_marked_object(curr_block, &mark_bit_idx); + + } + curr_block = fspace_get_next_copy_block(fspace, curr_block); + } + + mspace->free_block_idx = dest_block->block_idx+1; + + return TRUE; +} + +#include "../verify/verify_live_heap.h" + +void fspace_copy_collect(Collector* collector, Fspace* fspace) +{ + Block_Header* curr_block = fspace_get_first_copy_block(fspace); + + while( curr_block ){ + unsigned int mark_bit_idx; + Partial_Reveal_Object* p_obj = block_get_first_marked_object(curr_block, &mark_bit_idx); + + while( p_obj ){ + assert( obj_is_marked_in_vt(p_obj)); + obj_unmark_in_vt(p_obj); + + unsigned int obj_size = vm_object_size(p_obj); + Partial_Reveal_Object *p_target_obj = get_forwarding_pointer_in_obj_info(p_obj); + memmove(p_target_obj, p_obj, obj_size); + + if (verify_live_heap) + /* we forwarded it, we need remember it for verification */ + event_collector_move_obj(p_obj, p_target_obj, collector); + + set_obj_info(p_target_obj, 0); + + p_obj = block_get_next_marked_object(curr_block, &mark_bit_idx); + } + + curr_block = fspace_get_next_copy_block(fspace, curr_block); + } + + fspace_restore_obj_info(fspace); + reset_fspace_for_allocation(fspace); + + return; +} + +void gc_gen_update_repointed_refs(Collector* collector); + +void mark_copy_fspace(Collector* collector) +{ + GC* gc = collector->gc; + Fspace* fspace = (Fspace*)collector->collect_space; + + /* FIXME:: Single-threaded mark-copying for fspace currently */ + + /* Pass 1: mark all live objects in heap, and save all the slots that + have references that are going to be repointed */ + mark_scan_heap(collector); + + /* Pass 2: assign each live fspace object a new location */ + fspace_compute_object_target(collector, fspace); + + gc_gen_update_repointed_refs(collector); + + /* FIXME:: Pass 2 and 3 can be merged into one pass */ + /* Pass 3: copy live fspace object to new location */ + fspace_copy_collect(collector, fspace); + + return; +} Index: src/trace_forward/fspace.cpp =================================================================== --- src/trace_forward/fspace.cpp (revision 465167) +++ src/trace_forward/fspace.cpp (working copy) @@ -30,15 +30,109 @@ Boolean forward_first_half;; void* object_forwarding_boundary=NULL; +void fspace_save_reloc(Fspace* fspace, Partial_Reveal_Object** p_ref) +{ + Block_Header* block = GC_BLOCK_HEADER(p_ref); + block->reloc_table->push_back(p_ref); + return; +} -void fspace_destruct(Fspace *fspace) +void fspace_update_reloc(Fspace* fspace) { - port_vmem_decommit(fspace->heap_start, fspace->committed_heap_size, fspace->gc->allocated_memory); - STD_FREE(fspace->mark_table); - STD_FREE(fspace); - + SlotVector* reloc_table; + /* update refs in fspace */ + Block* blocks = fspace->blocks; + for(unsigned int i=0; i < fspace->num_managed_blocks; i++){ + Block_Header* block = (Block_Header*)&(blocks[i]); + reloc_table = block->reloc_table; + for(unsigned int j=0; j < reloc_table->size(); j++){ + Partial_Reveal_Object** p_ref = (*reloc_table)[j]; + Partial_Reveal_Object* p_target_obj = get_forwarding_pointer_in_obj_info(*p_ref); + *p_ref = p_target_obj; + } + reloc_table->clear(); + } + + return; +} + +Boolean fspace_mark_object(Fspace* fspace, Partial_Reveal_Object *p_obj) +{ + obj_mark_in_vt(p_obj); + + unsigned int obj_word_index = OBJECT_WORD_INDEX_TO_MARKBIT_TABLE(p_obj); + unsigned int obj_offset_in_word = OBJECT_WORD_OFFSET_IN_MARKBIT_TABLE(p_obj); + + unsigned int *p_word = &(GC_BLOCK_HEADER(p_obj)->mark_table[obj_word_index]); + unsigned int word_mask = (1<mark_table[obj_word_index]); + unsigned int word_mask = (1<blocks; + for(unsigned int i=0; i < fspace->num_managed_blocks; i++){ + Block_Header* block = (Block_Header*)&(blocks[i]); + delete block->reloc_table; + block->reloc_table = NULL; + } + + return; +} + +static void fspace_init_blocks(Fspace* fspace) +{ + Block* blocks = (Block*)fspace->heap_start; + Block_Header* last_block = (Block_Header*)blocks; + unsigned int start_idx = fspace->first_block_idx; + for(unsigned int i=0; i < fspace->num_managed_blocks; i++){ + Block_Header* block = (Block_Header*)&(blocks[i]); + block->free = (void*)((unsigned int)block + GC_BLOCK_HEADER_SIZE_BYTES); + block->ceiling = (void*)((unsigned int)block + GC_BLOCK_SIZE_BYTES); + block->base = block->free; + block->block_idx = i + start_idx; + block->status = BLOCK_FREE; + block->reloc_table = new SlotVector(); + last_block->next = block; + last_block = block; + } + last_block->next = NULL; + fspace->blocks = blocks; + + return; +} + struct GC_Gen; void gc_set_nos(GC_Gen* gc, Space* space); void fspace_initialize(GC* gc, void* start, unsigned int fspace_size) @@ -47,133 +141,109 @@ Fspace* fspace = (Fspace *)STD_MALLOC(sizeof(Fspace)); assert(fspace); memset(fspace, 0, sizeof(Fspace)); + + fspace->reserved_heap_size = fspace_size; + fspace->num_total_blocks = fspace_size >> GC_BLOCK_SHIFT_COUNT; void* reserved_base = start; int status = port_vmem_commit(&reserved_base, fspace_size, gc->allocated_memory); assert(status == APR_SUCCESS && reserved_base == start); - + memset(reserved_base, 0, fspace_size); - - fspace->block_size_bytes = GC_BLOCK_SIZE_BYTES; - fspace->committed_heap_size = fspace->reserved_heap_size = fspace_size; + fspace->committed_heap_size = fspace_size; + fspace->heap_start = reserved_base; + fspace->heap_end = (void *)((unsigned int)reserved_base + fspace->reserved_heap_size); + fspace->num_managed_blocks = fspace_size >> GC_BLOCK_SHIFT_COUNT; - fspace->heap_start = (void *)start; - fspace->heap_end = (void *)((POINTER_SIZE_INT) start + fspace_size); - - fspace->num_collections = 0; - - fspace->alloc_free = fspace->heap_start; - fspace->alloc_ceiling = fspace->heap_end; - forward_first_half = TRUE; - object_forwarding_boundary = (void *)((((POINTER_SIZE_INT)start + (unsigned int)(fspace_size*NURSERY_OBJECT_FORWARDING_RATIO))>>7)<<7); - - /* mark_table: 1. MAJOR_COLLECTION mark and copy nursery, 2. MINOR_COLLECTION mark non-forwarded part */ - fspace->mark_table_size = fspace_size>>5; - fspace->mark_table = (unsigned int*)STD_MALLOC(fspace->mark_table_size); - fspace->mark_table_half_boundary = fspace->mark_table + (((unsigned int)(fspace_size*NURSERY_OBJECT_FORWARDING_RATIO))>>7); - memset(fspace->mark_table, 0, fspace->mark_table_size); - + fspace->first_block_idx = GC_BLOCK_INDEX_FROM(gc->heap_start, reserved_base); + fspace->ceiling_block_idx = fspace->first_block_idx + fspace->num_managed_blocks - 1; + + fspace->num_used_blocks = 0; + fspace->free_block_idx = fspace->first_block_idx; + + fspace_init_blocks(fspace); + + fspace->obj_info_map = new ObjectMap(); fspace->mark_object_func = fspace_mark_object; fspace->save_reloc_func = fspace_save_reloc; fspace->update_reloc_func = fspace_update_reloc; - fspace->remslot_sets = new std::vector(); - fspace->remobj_sets = new std::vector(); - fspace->rem_sets_lock = FREE_LOCK; - - fspace->reloc_table = new SlotVector(); - fspace->obj_info_map = new ObjectMap(); - fspace->move_object = TRUE; + fspace->num_collections = 0; fspace->gc = gc; gc_set_nos((GC_Gen*)gc, (Space*)fspace); + /* above is same as Mspace init --> */ + + fspace->remslot_sets = new std::vector(); + fspace->rem_sets_lock = FREE_LOCK; nos_boundary = fspace->heap_end; + forward_first_half = TRUE; + object_forwarding_boundary = (void*)&fspace->blocks[fspace->first_block_idx + (unsigned int)(fspace->num_managed_blocks * NURSERY_OBJECT_FORWARDING_RATIO)]; + return; } -Boolean fspace_mark_object(Fspace* fspace, Partial_Reveal_Object *p_obj) +void fspace_destruct(Fspace *fspace) { - assert(obj_belongs_to_space(p_obj, (Space*)fspace)); - - //offset in byte - unsigned int offset = (POINTER_SIZE_INT)p_obj - (POINTER_SIZE_INT)fspace->heap_start; - assert( ((offset>>2)<<2)==offset); - - offset >>= 2; //offset in word - unsigned int bit_off_in_word = offset - ((offset>>5)<<5); - unsigned int* pos = fspace->mark_table + (offset>>5); - - if( NURSERY_OBJECT_FORWARDING_RATIO != FORWARD_ALL && fspace->gc->collect_kind != MAJOR_COLLECTION ) - assert(forward_first_half?(pos >= fspace->mark_table_half_boundary):(posmark_table_half_boundary)); - - unsigned int word = *pos; - unsigned int result = word | (1<heap_start, fspace->committed_heap_size, fspace->gc->allocated_memory); + STD_FREE(fspace); + } - -void fspace_clear_mark_bits(Fspace* fspace) -{ - unsigned int* mark_table = fspace->mark_table; - unsigned int* fspace_marked_half = (unsigned int*)fspace->heap_start; - unsigned int* table_end = fspace->mark_table_half_boundary; - Partial_Reveal_Object* p_obj = NULL; - - if( forward_first_half ){ - //forward frist half, so the second half is marked - table_end = (unsigned int*)((POINTER_SIZE_INT)mark_table + fspace->mark_table_size); - mark_table = fspace->mark_table_half_boundary; - fspace_marked_half = (unsigned int*)object_forwarding_boundary; - } - - unsigned j=0; - while( (mark_table + j) < table_end){ - unsigned int markbits = *(mark_table+j); - if(!markbits){ j++; continue; } - unsigned int k=0; - while(k<32){ - if( !(markbits& (1<gc->collect_kind == MAJOR_COLLECTION ){ - fspace->alloc_free = fspace->heap_start; - fspace->alloc_ceiling = fspace->heap_end; + fspace->gc->collect_kind == MAJOR_COLLECTION ) + { + fspace->free_block_idx = fspace->first_block_idx; + fspace->ceiling_block_idx = fspace->first_block_idx + fspace->num_managed_blocks - 1; forward_first_half = TRUE; /* only useful for not-FORWARD_ALL*/ }else{ if(forward_first_half){ - fspace->alloc_free = fspace->heap_start; - fspace->alloc_ceiling = object_forwarding_boundary; + fspace->free_block_idx = fspace->first_block_idx; + fspace->ceiling_block_idx = ((Block_Header*)object_forwarding_boundary)->block_idx - 1; }else{ - fspace->alloc_free = object_forwarding_boundary; - fspace->alloc_ceiling = fspace->heap_end; + fspace->free_block_idx = ((Block_Header*)object_forwarding_boundary)->block_idx; + fspace->ceiling_block_idx = fspace->first_block_idx + fspace->num_managed_blocks - 1; } forward_first_half = ~forward_first_half; - /* clear all the marking bits of the remaining objects in fspace */ - fspace_clear_mark_bits(fspace); } + + unsigned int first_idx = fspace->free_block_idx; + unsigned int last_idx = fspace->ceiling_block_idx; + Block* blocks = fspace->blocks; + unsigned int num_freed = 0; + for(unsigned int i = first_idx; i <= last_idx; i++){ + Block_Header* block = (Block_Header*)&(blocks[i]); + if(block->status == BLOCK_FREE) continue; + block_clear_mark_table(block); + block->status = BLOCK_FREE; + block->free = GC_BLOCK_BODY(block); + num_freed ++; + } + fspace->num_used_blocks = fspace->num_used_blocks - num_freed; + } + +void collector_execute_task(GC* gc, TaskType task_func, Space* space); + +/* world is stopped when starting fspace_collection */ +void fspace_collection(Fspace *fspace) +{ + fspace->num_collections++; + + GC* gc = fspace->gc; + + if(gc_requires_barriers()){ + /* generational GC. Only trace (mark) nos */ + collector_execute_task(gc, (TaskType)trace_forward_fspace, (Space*)fspace); + }else{ + /* non-generational GC. Mark the whole heap (nos, mos, and los) */ + collector_execute_task(gc, (TaskType)mark_copy_fspace, (Space*)fspace); + } + + return; +} Index: src/trace_forward/fspace_forward.cpp =================================================================== --- src/trace_forward/fspace_forward.cpp (revision 465167) +++ src/trace_forward/fspace_forward.cpp (working copy) @@ -1,256 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#include "fspace.h" -#include "../thread/collector.h" -#include "../common/interior_pointer.h" - -static Boolean fspace_object_to_be_forwarded(Partial_Reveal_Object *p_obj, Fspace *fspace) -{ - assert(obj_belongs_to_space(p_obj, (Space*)fspace)); - return forward_first_half? (p_obj < object_forwarding_boundary):(p_obj>=object_forwarding_boundary); -} - -static void scan_slot(Collector* collector, Partial_Reveal_Object **p_ref) -{ - Partial_Reveal_Object *p_obj = *p_ref; - TraceStack *ts = collector->trace_stack; - - if (p_obj == NULL) return; - - /* the slot can be in tspace or fspace, we don't care. - we care only if the reference in the slot is pointing to fspace */ - if (obj_belongs_to_space(p_obj, collector->collect_space)) { - ts->push(p_ref); - } - - return; -} - -static void scan_object(Collector* collector, Partial_Reveal_Object *p_obj) -{ - if (!object_has_slots(p_obj)) return; - - void *slot; - - /* scan array object */ - if (object_is_array(p_obj)) { - Partial_Reveal_Object* array = p_obj; - assert(!obj_is_primitive_array(array)); - - int32 array_length = vector_get_length((Vector_Handle) array); - for (int i = 0; i < array_length; i++) { - slot = vector_get_element_address_ref((Vector_Handle) array, i); - scan_slot(collector, (Partial_Reveal_Object **)slot); - } - return; - } - - /* scan non-array object */ - int *offset_scanner = init_object_scanner(p_obj); - while (true) { - slot = offset_get_ref(offset_scanner, p_obj); - if (slot == NULL) break; - - scan_slot(collector, (Partial_Reveal_Object **)slot); - offset_scanner = offset_next_ref(offset_scanner); - } - - return; -} - -/* At this point, p_ref can be in anywhere like root, and other spaces, - * but *p_ref must be in fspace, since only slot which points to - * object in fspace could be added into TraceStack */ -#include "../verify/verify_live_heap.h" - -static void trace_object(Collector* collector, Partial_Reveal_Object **p_ref) -{ - Space* space = collector->collect_space; - Partial_Reveal_Object *p_obj = *p_ref; - - assert(p_obj); - assert(obj_belongs_to_space(p_obj, space)); - - /* Fastpath: object has already been forwarded, update the ref slot */ - if(obj_is_forwarded_in_vt(p_obj)) { - assert(!obj_is_marked_in_vt(p_obj)); - *p_ref = obj_get_forwarding_pointer_in_vt(p_obj); - return; - } - - /* only mark the objects that will remain in fspace */ - if (!fspace_object_to_be_forwarded(p_obj, (Fspace*)space)) { - assert(!obj_is_forwarded_in_vt(p_obj)); - /* this obj remains in fspace, remember its ref slot for next GC. */ - if( !address_belongs_to_space(p_ref, space) ){ - collector->this_cycle_remset->push_back(p_ref); - } - - if(!obj_is_marked_in_vt(p_obj)){ - fspace_mark_object((Fspace*)space, p_obj); - scan_object(collector, p_obj); - } - return; - } - - /* following is the logic for forwarding */ - Partial_Reveal_Object* p_target_obj = collector_forward_object(collector, p_obj); - - /* if it is forwarded by other already, it is ok */ - if(!p_target_obj){ - *p_ref = obj_get_forwarding_pointer_in_vt(p_obj); - return; - } - /* otherwise, we successfully forwarded */ - *p_ref = p_target_obj; - - /* we forwarded it, we need remember it for verification. FIXME:: thread id */ - if(verify_live_heap) { - event_collector_move_obj(p_obj, p_target_obj, collector); - } - - scan_object(collector, p_target_obj); - return; -} - -/* trace the root references from root set and remember sets */ -void trace_root(Collector* collector, Partial_Reveal_Object **ref) -{ - assert(*ref); - assert(obj_belongs_to_space(*ref, collector->collect_space)); - - TraceStack *ts = collector->trace_stack; - ts->push(ref); - - while(!ts->empty()) { - Partial_Reveal_Object **p_ref = ts->top(); - ts->pop(); - assert(p_ref); - trace_object(collector, p_ref); - } -} - -static void scan_object_slot(Collector* collector, Partial_Reveal_Object *p_obj) -{ - Space* space = collector->collect_space; - - if ( obj_belongs_to_space(p_obj, space)) return; - - if (!object_has_slots(p_obj)) return; - - if (object_is_array(p_obj)) { - assert(!obj_is_primitive_array(p_obj)); - - int32 array_length = vector_get_length((Vector_Handle) p_obj); - for (int i = 0; i < array_length; i++) { - Partial_Reveal_Object** slot = (Partial_Reveal_Object**)vector_get_element_address_ref((Vector_Handle) p_obj, i); - if (obj_belongs_to_space(*slot, space)) - trace_root(collector, slot); - } - } else { - int *offset_scanner = init_object_scanner(p_obj); - while (true) { - Partial_Reveal_Object** slot = (Partial_Reveal_Object**)offset_get_ref(offset_scanner, p_obj); - if (slot == NULL) break; - if ((*slot != NULL) && (obj_belongs_to_space(*slot, space))) - trace_root(collector, slot); - - offset_scanner = offset_next_ref(offset_scanner); - } - } - return; -} - -static void collector_scan_remsets(Collector* collector) -{ - Fspace* fspace = (Fspace*)collector->collect_space; - - HashSet remslot_hash; - - /* find root slots saved by 1. active mutators, 2. exited mutators, 3. last cycle collectors */ - for(unsigned int i=0; i< fspace->remslot_sets->size(); i++) { - RemslotSet* remslot = (*fspace->remslot_sets)[i]; - for (unsigned int j = 0; j < remslot->size(); j++) { - Partial_Reveal_Object **ref = (*remslot)[j]; - assert(ref); - if(*ref == NULL) continue; - if (obj_belongs_to_space(*ref, (Space*)fspace)) { - if (remslot_hash.find(ref) == remslot_hash.end()) { - remslot_hash.insert(ref); - trace_root(collector, ref); - } - } - } - remslot->clear(); - } - fspace->remslot_sets->clear(); - - HashSet remobj_hash; - - /* find root slots from the remobjs saved by 1. active mutators 2. exited mutators */ - for(unsigned int i=0; iremobj_sets->size(); i++) { - RemobjSet *remobj = (*fspace->remobj_sets)[i]; - for(unsigned int j=0; jsize(); j++) { - Partial_Reveal_Object *obj = (*remobj)[j]; - if (remobj_hash.find(obj) == remobj_hash.end()) { - remobj_hash.insert(obj); - scan_object_slot(collector, obj); - } - } - remobj->clear(); - } - fspace->remobj_sets->clear(); - - return; -} - -static void update_relocated_refs(Collector* collector) -{ - update_rootset_interior_pointer(); -} - -static void trace_forward_fspace(Collector* collector) -{ - GC* gc = collector->gc; - Fspace* space = (Fspace*)collector->collect_space; - - /* FIXME:: Single-threaded trace-forwarding for fspace currently */ - - space->remslot_sets->push_back(gc->root_set); - collector_scan_remsets(collector); - update_relocated_refs(collector); - reset_fspace_for_allocation(space); - - return; - -} - -/* world is stopped when starting fspace_collection */ -void fspace_collection(Fspace *fspace) -{ - fspace->num_collections++; - - GC* gc = fspace->gc; - - collector_execute_task(gc, (TaskType)trace_forward_fspace, (Space*)fspace); - - return; -} Index: src/trace_forward/fspace.h =================================================================== --- src/trace_forward/fspace.h (revision 465167) +++ src/trace_forward/fspace.h (working copy) @@ -47,60 +47,57 @@ void (*save_reloc_func)(Fspace* space, Partial_Reveal_Object** p_ref); void (*update_reloc_func)(Fspace* space); /* END of Space --> */ - - /* places to start and stop alloc */ - volatile void* alloc_free; - void* alloc_ceiling; - - unsigned int block_size_bytes; + + Block* blocks; /* short-cut for mpsace blockheader access, not mandatory */ - unsigned int* mark_table; //table to keep mark_bits of fspace - unsigned int mark_table_size; - unsigned int* mark_table_half_boundary; + /* FIXME:: the block indices should be replaced with block header addresses */ + unsigned int first_block_idx; + unsigned int ceiling_block_idx; + volatile unsigned int free_block_idx; + unsigned int num_used_blocks; + unsigned int num_managed_blocks; + unsigned int num_total_blocks; + + /* during compaction, save non-zero obj_info who's overwritten by forwarding pointer */ + ObjectMap* obj_info_map; + /* END of Blocked_Space --> */ + /* saved remsets of collectors */ /* saved remsets of exited mutators */ std::vector *remslot_sets; - std::vector *remobj_sets; SpinLock rem_sets_lock; - - /* support other space moving collection */ - SlotVector* reloc_table; - ObjectMap* obj_info_map; } Fspace; void fspace_initialize(GC* gc, void* start, unsigned int fspace_size); void fspace_destruct(Fspace *fspace); -inline unsigned int fspace_free_memory_size(Fspace* fspace) -{ return (unsigned int)fspace->alloc_ceiling - (unsigned int)fspace->alloc_free; } +inline Boolean fspace_has_free_block(Fspace* fspace){ return fspace->free_block_idx <= fspace->ceiling_block_idx; } +inline unsigned int fspace_free_memory_size(Fspace* fspace){ return GC_BLOCK_SIZE_BYTES * (fspace->ceiling_block_idx - fspace->free_block_idx + 1); } +inline Boolean fspace_used_memory_size(Fspace* fspace){ return GC_BLOCK_SIZE_BYTES * fspace->num_used_blocks; } -inline unsigned int fspace_used_memory_size(Fspace* fspace) -{ return (unsigned int)fspace->alloc_free - (unsigned int)fspace->heap_start; } -void* fspace_alloc(unsigned size, Alloc_Context *alloc_ctx); +void* fspace_alloc(unsigned size, Allocator *allocator); Boolean fspace_mark_object(Fspace* fspace, Partial_Reveal_Object *p_obj); -void fspace_clear_mark_bits(Fspace* fspace); - void fspace_save_reloc(Fspace* fspace, Partial_Reveal_Object** p_ref); void fspace_update_reloc(Fspace* fspace); -void fspace_restore_obj_info(Fspace* fspace); +void reset_fspace_for_allocation(Fspace* fspace); + +inline Block_Header* fspace_get_first_copy_block(Fspace* fspace) +{ return (Block_Header*)fspace->blocks; } + +inline Block_Header* fspace_get_next_copy_block(Fspace* fspace, Block_Header* block) +{ return block->next; } + + +Boolean fspace_compute_object_target(Collector* collector, Fspace* fspace); void fspace_copy_collect(Collector* collector, Fspace* fspace); -void space_copy_remset_slots(Fspace* space, RootSet* copy_rootset); -void space_update_remsets(Fspace* space); -void fspace_collection(Fspace* fspace); -void reset_fspace_for_allocation(Fspace* fspace); +void trace_forward_fspace(Collector* collector); +void mark_copy_fspace(Collector* collector); -inline unsigned int fspace_allocated_size(Fspace* fspace) -{ - return (unsigned int)fspace->alloc_ceiling - (unsigned int)fspace->alloc_free; -} +void fspace_collection(Fspace* fspace); -inline Boolean fspace_has_free_block(Fspace* fspace) -{ - return ((POINTER_SIZE_INT)fspace->alloc_free + fspace->block_size_bytes) <= (POINTER_SIZE_INT)fspace->alloc_ceiling; -} #endif // _FROM_SPACE_H_ Index: src/trace_forward/fspace_collect_forward.cpp =================================================================== --- src/trace_forward/fspace_collect_forward.cpp (revision 0) +++ src/trace_forward/fspace_collect_forward.cpp (revision 0) @@ -0,0 +1,200 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#include "fspace.h" +#include "../thread/collector.h" + +static Boolean fspace_object_to_be_forwarded(Partial_Reveal_Object *p_obj, Fspace *fspace) +{ + assert(obj_belongs_to_space(p_obj, (Space*)fspace)); + return forward_first_half? (p_obj < object_forwarding_boundary):(p_obj>=object_forwarding_boundary); +} + +static void scan_slot(Collector* collector, Partial_Reveal_Object **p_ref) +{ + Partial_Reveal_Object *p_obj = *p_ref; + TraceStack *ts = collector->trace_stack; + + if (p_obj == NULL) return; + + /* the slot can be in tspace or fspace, we don't care. + we care only if the reference in the slot is pointing to fspace */ + if (obj_belongs_to_space(p_obj, collector->collect_space)) { + ts->push(p_ref); + } + + return; +} + +static void scan_object(Collector* collector, Partial_Reveal_Object *p_obj) +{ + if (!object_has_slots(p_obj)) return; + + void *slot; + + /* scan array object */ + if (object_is_array(p_obj)) { + Partial_Reveal_Object* array = p_obj; + assert(!obj_is_primitive_array(array)); + + int32 array_length = vector_get_length((Vector_Handle) array); + for (int i = 0; i < array_length; i++) { + slot = vector_get_element_address_ref((Vector_Handle) array, i); + scan_slot(collector, (Partial_Reveal_Object **)slot); + } + return; + } + + /* scan non-array object */ + int *offset_scanner = init_object_scanner(p_obj); + while (true) { + slot = offset_get_ref(offset_scanner, p_obj); + if (slot == NULL) break; + + scan_slot(collector, (Partial_Reveal_Object **)slot); + offset_scanner = offset_next_ref(offset_scanner); + } + + return; +} + +/* At this point, p_ref can be in anywhere like root, and other spaces, + * but *p_ref must be in fspace, since only slot which points to + * object in fspace could be added into TraceStack */ +#include "../verify/verify_live_heap.h" + +static void trace_object(Collector* collector, Partial_Reveal_Object **p_ref) +{ + Space* space = collector->collect_space; + Partial_Reveal_Object *p_obj = *p_ref; + + assert(p_obj); + assert(obj_belongs_to_space(p_obj, space)); + + /* Fastpath: object has already been forwarded, update the ref slot */ + if(obj_is_forwarded_in_vt(p_obj)) { + assert(!obj_is_marked_in_vt(p_obj)); + *p_ref = obj_get_forwarding_pointer_in_vt(p_obj); + return; + } + + /* only mark the objects that will remain in fspace */ + if (!fspace_object_to_be_forwarded(p_obj, (Fspace*)space)) { + assert(!obj_is_forwarded_in_vt(p_obj)); + /* this obj remains in fspace, remember its ref slot for next GC. */ + if( !address_belongs_to_space(p_ref, space) ) + collector->this_cycle_remset->push_back(p_ref); + + if(fspace_mark_object((Fspace*)space, p_obj)) + scan_object(collector, p_obj); + + return; + } + + /* following is the logic for forwarding */ + Partial_Reveal_Object* p_target_obj = collector_forward_object(collector, p_obj); + + /* if it is forwarded by other already, it is ok */ + if(!p_target_obj){ + *p_ref = obj_get_forwarding_pointer_in_vt(p_obj); + return; + } + /* otherwise, we successfully forwarded */ + *p_ref = p_target_obj; + + /* we forwarded it, we need remember it for verification. FIXME:: thread id */ + if(verify_live_heap) { + event_collector_move_obj(p_obj, p_target_obj, collector); + } + + scan_object(collector, p_target_obj); + return; +} + +/* trace the root references from root set and remember sets */ +void trace_root(Collector* collector, Partial_Reveal_Object **ref) +{ + assert(*ref); + assert(obj_belongs_to_space(*ref, collector->collect_space)); + + TraceStack *ts = collector->trace_stack; + ts->push(ref); + + while(!ts->empty()) { + Partial_Reveal_Object **p_ref = ts->top(); + ts->pop(); + assert(p_ref); + trace_object(collector, p_ref); + } +} + +static void collector_trace_remsets(Collector* collector) +{ + Fspace* fspace = (Fspace*)collector->collect_space; + + HashSet remslot_hash; + + /* find root slots saved by 1. active mutators, 2. exited mutators, 3. last cycle collectors */ + for(unsigned int i=0; i< fspace->remslot_sets->size(); i++) { + RemslotSet* remslot = (*fspace->remslot_sets)[i]; + for (unsigned int j = 0; j < remslot->size(); j++) { + Partial_Reveal_Object **ref = (*remslot)[j]; + assert(ref); + if(*ref == NULL) continue; + if (obj_belongs_to_space(*ref, (Space*)fspace)) { + if (remslot_hash.find(ref) == remslot_hash.end()) { + remslot_hash.insert(ref); + trace_root(collector, ref); + } + } + } + remslot->clear(); + } + fspace->remslot_sets->clear(); + + return; +} + +void update_rootset_interior_pointer(); + +static void update_relocated_refs(Collector* collector) +{ + update_rootset_interior_pointer(); +} + +void trace_forward_fspace(Collector* collector) +{ + GC* gc = collector->gc; + Fspace* space = (Fspace*)collector->collect_space; + + /* FIXME:: Single-threaded trace-forwarding for fspace currently */ + + space->remslot_sets->push_back(gc->root_set); + collector_trace_remsets(collector); + + update_relocated_refs(collector); + reset_fspace_for_allocation(space); + + return; + +} + + + Index: src/trace_forward/fspace_alloc.cpp =================================================================== --- src/trace_forward/fspace_alloc.cpp (revision 465167) +++ src/trace_forward/fspace_alloc.cpp (working copy) @@ -20,66 +20,71 @@ #include "fspace.h" -static Boolean fspace_alloc_block(Fspace* fspace, Alloc_Context *alloc_ctx) +static Boolean fspace_alloc_block(Fspace* fspace, Allocator* allocator) { - - void* old_free_pos = (void*)fspace->alloc_free; - void* new_free_pos = (void*)((POINTER_SIZE_INT)old_free_pos + fspace->block_size_bytes); - while ( fspace_has_free_block(fspace) ){ - /* There are enough space to hold a TLB in fspace, try to get it */ - POINTER_SIZE_INT temp = atomic_cas32((volatile uint32 *)&fspace->alloc_free, \ - (POINTER_SIZE_INT)new_free_pos, (POINTER_SIZE_INT)old_free_pos); - - if(temp != (POINTER_SIZE_INT)old_free_pos){ - old_free_pos = (void*)fspace->alloc_free; - new_free_pos = (void*)((POINTER_SIZE_INT)old_free_pos + fspace->block_size_bytes); + Block_Header* alloc_block = (Block_Header* )allocator->alloc_block; + /* put back the used block */ + if(alloc_block != NULL){ /* it is NULL at first time */ + assert(alloc_block->status == BLOCK_IN_USE); + alloc_block->status = BLOCK_USED; + alloc_block->free = allocator->free; + } + + /* now try to get a new block */ + unsigned int old_free_idx = fspace->free_block_idx; + unsigned int new_free_idx = old_free_idx+1; + while(old_free_idx <= fspace->ceiling_block_idx){ + unsigned int allocated_idx = atomic_cas32(&fspace->free_block_idx, new_free_idx, old_free_idx); + if(allocated_idx != old_free_idx){ /* if failed */ + old_free_idx = fspace->free_block_idx; + new_free_idx = old_free_idx+1; continue; } + /* ok, got one */ + alloc_block = (Block_Header*)&(fspace->blocks[allocated_idx - fspace->first_block_idx]); + assert(alloc_block->status == BLOCK_FREE); + alloc_block->status = BLOCK_IN_USE; + fspace->num_used_blocks++; + memset(alloc_block->free, 0, GC_BLOCK_BODY_SIZE_BYTES); - alloc_ctx->free = (char*)old_free_pos; - alloc_ctx->ceiling = (char*)old_free_pos + fspace->block_size_bytes; - memset(old_free_pos, 0, fspace->block_size_bytes); + /* set allocation context */ + allocator->free = alloc_block->free; + allocator->ceiling = alloc_block->ceiling; + allocator->alloc_block = (Block*)alloc_block; return TRUE; } + + return FALSE; - return FALSE; } + /* FIXME:: the collection should be seperated from the alloation */ struct GC_Gen; -Space* gc_get_nos(GC_Gen* gc); void gc_gen_reclaim_heap(GC_Gen* gc, unsigned int cause); -void* fspace_alloc(unsigned size, Alloc_Context *alloc_ctx) +void* fspace_alloc(unsigned size, Allocator *allocator) { void* p_return = NULL; /* First, try to allocate object from TLB (thread local block) */ - p_return = thread_local_alloc(size, alloc_ctx); + p_return = thread_local_alloc(size, allocator); if (p_return) return p_return; - - /* grab another TLB */ - Fspace* fspace = (Fspace*)alloc_ctx->alloc_space; -retry_grab_block: - if ( !fspace_has_free_block(fspace)) { /* can not get a new TLB, activate GC */ + /* ran out local block, grab a new one*/ + Fspace* fspace = (Fspace*)allocator->alloc_space; + while( !fspace_alloc_block(fspace, allocator)){ vm_gc_lock_enum(); /* after holding lock, try if other thread collected already */ if ( !fspace_has_free_block(fspace) ) { - gc_gen_reclaim_heap((GC_Gen*)alloc_ctx->gc, GC_CAUSE_NOS_IS_FULL); + gc_gen_reclaim_heap((GC_Gen*)allocator->gc, GC_CAUSE_NOS_IS_FULL); } vm_gc_unlock_enum(); } - - Boolean ok = fspace_alloc_block(fspace, alloc_ctx); - if(ok){ - p_return = thread_local_alloc(size, alloc_ctx); - assert(p_return); - return p_return; - } - - /* failed to get a TLB atomically */ - goto retry_grab_block; + p_return = thread_local_alloc(size, allocator); + + return p_return; + } Index: src/trace_forward/fspace_copy.cpp =================================================================== --- src/trace_forward/fspace_copy.cpp (revision 465167) +++ src/trace_forward/fspace_copy.cpp (working copy) @@ -1,174 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#include "fspace.h" - -/* copying of fspace is only for MAJOR_COLLECTION */ - -static void slot_update_to_forwarding_pointer(Partial_Reveal_Object **p_ref, Partial_Reveal_Object *p_obj) -{ - /* if obj is marked in MAJOR_COLLECTION, it is alive, and has forwarding pointer */ - if(!obj_is_marked_in_vt(p_obj)) return; - - *p_ref = get_forwarding_pointer_in_obj_info(p_obj); -} - -static void object_update_slots(Fspace* space, Partial_Reveal_Object *p_obj) -{ - if(obj_belongs_to_space(p_obj, (Space*)space)) return; - - if(!object_has_slots(p_obj)) return; - - if(object_is_array(p_obj)){ - assert(!obj_is_primitive_array(p_obj)); - - int32 array_length = vector_get_length((Vector_Handle) p_obj); - for (int i = 0; i < array_length; i++) { - Partial_Reveal_Object** p_ref = (Partial_Reveal_Object**)vector_get_element_address_ref((Vector_Handle) p_obj, i); - Partial_Reveal_Object* p_obj = *p_ref; - if(p_obj == NULL) continue; - if (obj_belongs_to_space(p_obj, (Space*)space)){ - slot_update_to_forwarding_pointer(p_ref, p_obj); - } - } - }else{ - int *offset_scanner = init_object_scanner(p_obj); - while (true) { - Partial_Reveal_Object** p_ref = (Partial_Reveal_Object**)offset_get_ref(offset_scanner, p_obj); - if (p_ref == NULL) break; - Partial_Reveal_Object* p_obj = *p_ref; - if(p_obj != NULL && obj_belongs_to_space(p_obj, (Space*)space)){ - slot_update_to_forwarding_pointer(p_ref, p_obj); - } - offset_scanner = offset_next_ref(offset_scanner); - } - } -} - -void space_update_remsets(Fspace* space) -{ - - for(unsigned int i=0; i< space->remslot_sets->size(); i++) { - RemslotSet* remslot = (*space->remslot_sets)[i]; - for (unsigned int j = 0; j < remslot->size(); j++) { - Partial_Reveal_Object** p_ref = (*remslot)[j]; - assert(p_ref); - Partial_Reveal_Object* p_obj = *p_ref; - if(p_obj == NULL) continue; - if (obj_belongs_to_space(p_obj, (Space*)space)){ - /* if obj is marked in MAJOR_COLLECTION, it is alive, and has forwarding pointer */ - if(obj_is_marked_in_vt(p_obj)){ - *p_ref = get_forwarding_pointer_in_obj_info(p_obj); - } - } - } - remslot->clear(); - } - space->remslot_sets->clear(); - - for(unsigned int i=0; iremobj_sets->size(); i++) { - RemobjSet *remobj = (*space->remobj_sets)[i]; - for(unsigned int j=0; jsize(); j++) { - Partial_Reveal_Object *obj = (*remobj)[j]; - object_update_slots(space, obj); - } - remobj->clear(); - } - space->remobj_sets->clear(); - - return; - -} - -void fspace_save_reloc(Fspace* fspace, Partial_Reveal_Object** p_ref) -{ - fspace->reloc_table->push_back(p_ref); -} - -void fspace_update_reloc(Fspace* fspace) -{ - SlotVector* reloc_table; - - reloc_table = fspace->reloc_table; - for(unsigned int j=0; j < reloc_table->size(); j++){ - Partial_Reveal_Object** p_ref = (*reloc_table)[j]; - Partial_Reveal_Object* p_target_obj = get_forwarding_pointer_in_obj_info(*p_ref); - *p_ref = p_target_obj; - } - reloc_table->clear(); - return; -} - -void fspace_restore_obj_info(Fspace* fspace) -{ - ObjectMap* objmap = fspace->obj_info_map; - ObjectMap::iterator obj_iter; - for( obj_iter=objmap->begin(); obj_iter!=objmap->end(); obj_iter++){ - Partial_Reveal_Object* p_target_obj = obj_iter->first; - Obj_Info_Type obj_info = obj_iter->second; - set_obj_info(p_target_obj, obj_info); - } - objmap->clear(); - return; -} - -#include "../verify/verify_live_heap.h" - -void fspace_copy_collect(Collector* collector, Fspace* fspace) -{ - unsigned int* mark_table = fspace->mark_table; - unsigned int* table_end = (unsigned int*)((POINTER_SIZE_INT)mark_table + fspace->mark_table_size); - unsigned int* fspace_start = (unsigned int*)fspace->heap_start; - Partial_Reveal_Object* p_obj = NULL; - - unsigned j=0; - while( (mark_table + j) < table_end){ - unsigned int markbits = *(mark_table+j); - if(!markbits){ j++; continue; } - unsigned int k=0; - while(k<32){ - if( !(markbits& (1<mark_table_size); - - reset_fspace_for_allocation(fspace); - - return; -} Index: src/thread/collector_alloc.cpp =================================================================== --- src/thread/collector_alloc.cpp (revision 465167) +++ src/thread/collector_alloc.cpp (working copy) @@ -1,57 +1,57 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#include "thread_alloc.h" - -void* mos_alloc(unsigned size, Alloc_Context *alloc_ctx); - -/* NOS forward obj to MOS in MINOR_COLLECTION */ -Partial_Reveal_Object* collector_forward_object(Collector* collector, Partial_Reveal_Object* p_obj) -{ - Partial_Reveal_VTable* vt = obj_get_vtraw(p_obj); - - /* forwarded by somebody else */ - if ((unsigned int)vt & FORWARDING_BIT_MASK){ - assert(!obj_is_marked_in_vt(p_obj)); - return NULL; - } - - /* else, take the obj by setting the forwarding flag atomically - we don't put a simple bit in vt because we need compute obj size later. */ - if ((unsigned int)vt != atomic_cas32((unsigned int*)obj_get_vtraw_addr(p_obj), ((unsigned int)vt|FORWARDING_BIT_MASK), (unsigned int)vt)) { - /* forwarded by other */ - assert( obj_is_forwarded_in_vt(p_obj) && !obj_is_marked_in_vt(p_obj)); - return NULL; - } - - /* we hold the object, now forward it */ - unsigned int size = vm_object_size(p_obj); - Partial_Reveal_Object* p_targ_obj = (Partial_Reveal_Object*)mos_alloc(size, (Alloc_Context*)collector); - /* mos should always has enough space to hold nos during collection */ - assert(p_targ_obj); - memcpy(p_targ_obj, p_obj, size); - - /* because p_obj has forwarding flag in its vt, we set it here */ - obj_set_forwarding_pointer_in_vt(p_obj, p_targ_obj); - obj_set_vt(p_targ_obj, (Allocation_Handle)vt); +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#include "thread_alloc.h" + +void* mos_alloc(unsigned size, Allocator *allocator); + +/* NOS forward obj to MOS in MINOR_COLLECTION */ +Partial_Reveal_Object* collector_forward_object(Collector* collector, Partial_Reveal_Object* p_obj) +{ + Partial_Reveal_VTable* vt = obj_get_vtraw(p_obj); + + /* forwarded by somebody else */ + if ((unsigned int)vt & FORWARDING_BIT_MASK){ + assert(!obj_is_marked_in_vt(p_obj)); + return NULL; + } + + /* else, take the obj by setting the forwarding flag atomically + we don't put a simple bit in vt because we need compute obj size later. */ + if ((unsigned int)vt != atomic_cas32((unsigned int*)obj_get_vtraw_addr(p_obj), ((unsigned int)vt|FORWARDING_BIT_MASK), (unsigned int)vt)) { + /* forwarded by other */ + assert( obj_is_forwarded_in_vt(p_obj) && !obj_is_marked_in_vt(p_obj)); + return NULL; + } + + /* we hold the object, now forward it */ + unsigned int size = vm_object_size(p_obj); + Partial_Reveal_Object* p_targ_obj = (Partial_Reveal_Object*)mos_alloc(size, (Allocator*)collector); + /* mos should always has enough space to hold nos during collection */ + assert(p_targ_obj); + memcpy(p_targ_obj, p_obj, size); + + /* because p_obj has forwarding flag in its vt, we set it here */ + obj_set_forwarding_pointer_in_vt(p_obj, p_targ_obj); + obj_set_vt(p_targ_obj, (Allocation_Handle)vt); return p_targ_obj; - -} \ No newline at end of file + +} Index: src/thread/mutator.h =================================================================== --- src/thread/mutator.h (revision 465167) +++ src/thread/mutator.h (working copy) @@ -1,46 +1,45 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#ifndef _MUTATOR_H_ -#define _MUTATOR_H_ - -#include "../common/gc_common.h" - -/* Mutator thread local information for GC */ -typedef struct Mutator { - /* <-- first couple of fields are overloaded as Alloc_Context */ - void* free; - void* ceiling; - void* curr_alloc_block; - Space* alloc_space; - GC* gc; - VmThreadHandle thread_handle; /* This thread; */ - /* END of Alloc_Context --> */ - - RemslotSet *remslot; - RemobjSet *remobj; - Mutator *next; /* The gc info area associated with the next active thread. */ -} Mutator; - -void mutator_initialize(GC* gc, void* tls_gc_info); -void mutator_destruct(GC* gc, void* tls_gc_info); -void mutator_reset(GC *gc); - -#endif /*ifndef _MUTATOR_H_ */ \ No newline at end of file +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#ifndef _MUTATOR_H_ +#define _MUTATOR_H_ + +#include "../common/gc_common.h" + +/* Mutator thread local information for GC */ +typedef struct Mutator { + /* <-- first couple of fields are overloaded as Allocator */ + void* free; + void* ceiling; + void* alloc_block; + Space* alloc_space; + GC* gc; + VmThreadHandle thread_handle; /* This thread; */ + /* END of Allocator --> */ + + RemslotSet *remslot; + Mutator *next; /* The gc info area associated with the next active thread. */ +} Mutator; + +void mutator_initialize(GC* gc, void* tls_gc_info); +void mutator_destruct(GC* gc, void* tls_gc_info); +void mutator_reset(GC *gc); + +#endif /*ifndef _MUTATOR_H_ */ Index: src/thread/mutator_alloc.cpp =================================================================== --- src/thread/mutator_alloc.cpp (revision 465167) +++ src/thread/mutator_alloc.cpp (working copy) @@ -32,9 +32,9 @@ assert(ah); if ( size > GC_OBJ_SIZE_THRESHOLD ) - p_obj = (Managed_Object_Handle)los_alloc(size, (Alloc_Context*)gc_tls); + p_obj = (Managed_Object_Handle)los_alloc(size, (Allocator*)gc_tls); else - p_obj = (Managed_Object_Handle)nos_alloc(size, (Alloc_Context*)gc_tls); + p_obj = (Managed_Object_Handle)nos_alloc(size, (Allocator*)gc_tls); assert(p_obj); obj_set_vt((Partial_Reveal_Object*)p_obj, ah); @@ -55,7 +55,7 @@ /* Try to allocate an object from the current Thread Local Block */ Managed_Object_Handle p_obj = NULL; - p_obj = (Managed_Object_Handle)thread_local_alloc(size, (Alloc_Context*)gc_tls); + p_obj = (Managed_Object_Handle)thread_local_alloc(size, (Allocator*)gc_tls); if(p_obj == NULL) return NULL; obj_set_vt((Partial_Reveal_Object*)p_obj, ah); Index: src/thread/collector.cpp =================================================================== --- src/thread/collector.cpp (revision 465167) +++ src/thread/collector.cpp (working copy) @@ -1,196 +1,196 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#include "open/vm_util.h" - -#include "collector.h" -#include "../mark_compact/mspace.h" - -static void collector_reset_thread(Collector *collector) -{ - collector->task_func = NULL; - - vm_reset_event(collector->task_assigned_event); - vm_reset_event(collector->task_finished_event); - - alloc_context_reset((Alloc_Context*)collector); - - return; -} - -static void wait_collector_to_finish(Collector *collector) -{ - vm_wait_event(collector->task_finished_event); -} - -static void notify_collector_to_work(Collector* collector) -{ - vm_set_event(collector->task_assigned_event); -} - -static void collector_wait_for_task(Collector *collector) -{ - vm_wait_event(collector->task_assigned_event); -} - -static void collector_notify_work_done(Collector *collector) -{ - vm_set_event(collector->task_finished_event); -} - -void gc_preprocess_collector(Collector*); -void gc_postprocess_collector(Collector*); -static void assign_collector_with_task(GC* gc, TaskType task_func, Space* space) -{ - unsigned int num_collectors_to_activate = gc->num_collectors; - for(unsigned int i=0; icollectors[i]; - - gc_preprocess_collector(collector); +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#include "open/vm_util.h" + +#include "collector.h" +#include "../mark_compact/mspace.h" + +static void collector_reset_thread(Collector *collector) +{ + collector->task_func = NULL; + + vm_reset_event(collector->task_assigned_event); + vm_reset_event(collector->task_finished_event); + + alloc_context_reset((Allocator*)collector); + + return; +} + +static void wait_collector_to_finish(Collector *collector) +{ + vm_wait_event(collector->task_finished_event); +} + +static void notify_collector_to_work(Collector* collector) +{ + vm_set_event(collector->task_assigned_event); +} + +static void collector_wait_for_task(Collector *collector) +{ + vm_wait_event(collector->task_assigned_event); +} + +static void collector_notify_work_done(Collector *collector) +{ + vm_set_event(collector->task_finished_event); +} + +void gc_preprocess_collector(Collector*); +void gc_postprocess_collector(Collector*); +static void assign_collector_with_task(GC* gc, TaskType task_func, Space* space) +{ + unsigned int num_collectors_to_activate = gc->num_collectors; + for(unsigned int i=0; icollectors[i]; + + gc_preprocess_collector(collector); collector_reset_thread(collector); - collector->task_func = task_func; - collector->collect_space = space; - notify_collector_to_work(collector); - } - gc->num_active_collectors = num_collectors_to_activate; - -} - -static void wait_collection_finish(GC* gc) -{ - unsigned int num_active_collectors = gc->num_active_collectors; - for(unsigned int i=0; icollectors[i]; - wait_collector_to_finish(collector); - gc_postprocess_collector(collector); - } - gc->num_active_collectors = 0; - -} - -static int collector_thread_func(void *arg) -{ - Collector *collector = (Collector *)arg; - assert(collector); - - while(true){ - /* Waiting for newly assigned task */ - collector_wait_for_task(collector); - - /* waken up and check for new task */ - TaskType task_func = collector->task_func; - if(task_func == NULL) return 1; - - task_func(collector); - - collector_notify_work_done(collector); - } - - return 0; -} - -static void collector_init_thread(Collector *collector) -{ - collector->trace_stack = new TraceStack(); /* only for MINOR_COLLECTION */ - collector->mark_stack = new MarkStack(); /* only for MAJOR_COLLECTION */ - - collector->last_cycle_remset = new RemslotSet(); - collector->last_cycle_remset->reserve(GC_NUM_ROOTS_HINT); - collector->last_cycle_remset->clear(); - - collector->this_cycle_remset = new RemslotSet(); - collector->this_cycle_remset->reserve(GC_NUM_ROOTS_HINT); - collector->this_cycle_remset->clear(); - - int status = vm_create_event(&collector->task_assigned_event,0,1); - assert(status == THREAD_OK); - - status = vm_create_event(&collector->task_finished_event,0,1); - assert(status == THREAD_OK); - - status = (unsigned int)vm_create_thread(NULL, - 0, 0, 0, - collector_thread_func, - (void*)collector); - - assert(status == THREAD_OK); - - return; -} - -static void collector_terminate_thread(Collector* collector) -{ - collector->task_func = NULL; /* NULL to notify thread exit */ - notify_collector_to_work(collector); - vm_thread_yield(); /* give collector time to die */ - - delete collector->trace_stack; - delete collector->last_cycle_remset; - delete collector->this_cycle_remset; - - return; -} - -void collector_destruct(GC* gc) -{ - for(unsigned int i=0; inum_collectors; i++) - { - Collector* collector = gc->collectors[i]; - collector_terminate_thread(collector); - STD_FREE(collector); - - } - - STD_FREE(gc->collectors); - return; -} - -struct GC_Gen; -unsigned int gc_get_processor_num(GC_Gen*); -void collector_initialize(GC* gc) -{ - unsigned int nthreads = gc_get_processor_num((GC_Gen*)gc); - - gc->num_collectors = 1; //FIXME:: nthreads; - gc->collectors = (Collector **) STD_MALLOC(sizeof(Collector *) * nthreads); - assert(gc->collectors); - - for (unsigned int i = 0; i < nthreads; i++) { - Collector* collector = (Collector *)STD_MALLOC(sizeof(Collector)); - assert(collector); - - collector->gc = gc; - collector_init_thread(collector); - - gc->collectors[i] = collector; - } - - return; -} - -void collector_execute_task(GC* gc, TaskType task_func, Space* space) -{ + collector->task_func = task_func; + collector->collect_space = space; + notify_collector_to_work(collector); + } + gc->num_active_collectors = num_collectors_to_activate; + +} + +static void wait_collection_finish(GC* gc) +{ + unsigned int num_active_collectors = gc->num_active_collectors; + for(unsigned int i=0; icollectors[i]; + wait_collector_to_finish(collector); + gc_postprocess_collector(collector); + } + gc->num_active_collectors = 0; + +} + +static int collector_thread_func(void *arg) +{ + Collector *collector = (Collector *)arg; + assert(collector); + + while(true){ + /* Waiting for newly assigned task */ + collector_wait_for_task(collector); + + /* waken up and check for new task */ + TaskType task_func = collector->task_func; + if(task_func == NULL) return 1; + + task_func(collector); + + collector_notify_work_done(collector); + } + + return 0; +} + +static void collector_init_thread(Collector *collector) +{ + collector->trace_stack = new TraceStack(); /* only for MINOR_COLLECTION */ + collector->mark_stack = new MarkStack(); /* only for MAJOR_COLLECTION */ + + collector->last_cycle_remset = new RemslotSet(); + collector->last_cycle_remset->reserve(GC_NUM_ROOTS_HINT); + collector->last_cycle_remset->clear(); + + collector->this_cycle_remset = new RemslotSet(); + collector->this_cycle_remset->reserve(GC_NUM_ROOTS_HINT); + collector->this_cycle_remset->clear(); + + int status = vm_create_event(&collector->task_assigned_event,0,1); + assert(status == THREAD_OK); + + status = vm_create_event(&collector->task_finished_event,0,1); + assert(status == THREAD_OK); + + status = (unsigned int)vm_create_thread(NULL, + 0, 0, 0, + collector_thread_func, + (void*)collector); + + assert(status == THREAD_OK); + + return; +} + +static void collector_terminate_thread(Collector* collector) +{ + collector->task_func = NULL; /* NULL to notify thread exit */ + notify_collector_to_work(collector); + vm_thread_yield(); /* give collector time to die */ + + delete collector->trace_stack; + delete collector->last_cycle_remset; + delete collector->this_cycle_remset; + + return; +} + +void collector_destruct(GC* gc) +{ + for(unsigned int i=0; inum_collectors; i++) + { + Collector* collector = gc->collectors[i]; + collector_terminate_thread(collector); + STD_FREE(collector); + + } + + STD_FREE(gc->collectors); + return; +} + +struct GC_Gen; +unsigned int gc_get_processor_num(GC_Gen*); +void collector_initialize(GC* gc) +{ + unsigned int nthreads = gc_get_processor_num((GC_Gen*)gc); + + gc->num_collectors = 1; //FIXME:: nthreads; + gc->collectors = (Collector **) STD_MALLOC(sizeof(Collector *) * nthreads); + assert(gc->collectors); + + for (unsigned int i = 0; i < nthreads; i++) { + Collector* collector = (Collector *)STD_MALLOC(sizeof(Collector)); + assert(collector); + + collector->gc = gc; + collector_init_thread(collector); + + gc->collectors[i] = collector; + } + + return; +} + +void collector_execute_task(GC* gc, TaskType task_func, Space* space) +{ assign_collector_with_task(gc, task_func, space); - wait_collection_finish(gc); - + wait_collection_finish(gc); + return; -} +} Index: src/thread/thread_alloc.h =================================================================== --- src/thread/thread_alloc.h (revision 465167) +++ src/thread/thread_alloc.h (working copy) @@ -21,37 +21,37 @@ #ifndef _THREAD_ALLOC_H_ #define _THREAD_ALLOC_H_ -#include "../common/gc_common.h" +#include "../common/gc_block.h" -typedef struct Alloc_Context{ +typedef struct Allocator{ void *free; void *ceiling; - void *curr_alloc_block; + Block *alloc_block; Space* alloc_space; GC *gc; VmThreadHandle thread_handle; /* This thread; */ -}Alloc_Context; +}Allocator; -inline Partial_Reveal_Object* thread_local_alloc(unsigned int size, Alloc_Context* alloc_ctx) +inline Partial_Reveal_Object* thread_local_alloc(unsigned int size, Allocator* allocator) { - Partial_Reveal_Object* p_return_obj=(Partial_Reveal_Object*)alloc_ctx->free; + Partial_Reveal_Object* p_return_obj=(Partial_Reveal_Object*)allocator->free; unsigned int new_free = size+(unsigned int)p_return_obj; - if (new_free <= (unsigned int)alloc_ctx->ceiling){ - alloc_ctx->free=(void*)new_free; + if (new_free <= (unsigned int)allocator->ceiling){ + allocator->free=(void*)new_free; return p_return_obj; } return NULL; } -inline void alloc_context_reset(Alloc_Context* alloc_ctx) +inline void alloc_context_reset(Allocator* allocator) { - alloc_ctx->free = NULL; - alloc_ctx->ceiling = NULL; - alloc_ctx->curr_alloc_block = NULL; + allocator->free = NULL; + allocator->ceiling = NULL; + allocator->alloc_block = NULL; return; } -#endif /* #ifndef _THREAD_ALLOC_H_ */ \ No newline at end of file +#endif /* #ifndef _THREAD_ALLOC_H_ */ Index: src/thread/collector.h =================================================================== --- src/thread/collector.h (revision 465167) +++ src/thread/collector.h (working copy) @@ -1,59 +1,59 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#ifndef _COLLECTOR_H_ -#define _COLLECTOR_H_ - -#include "../common/gc_common.h" - -typedef struct Collector{ - /* <-- first couple of fields are overloaded as Alloc_Context */ - void *free; - void *ceiling; - void *curr_alloc_block; - Space* alloc_space; - GC* gc; - VmThreadHandle thread_handle; /* This thread; */ - /* End of Alloc_Context --> */ - - Space* collect_space; - /* collector has remsets to remember those stored during copying */ - RemslotSet* last_cycle_remset; /* remembered in last cycle, used in this cycle as roots */ - RemslotSet* this_cycle_remset; /* remembered in this cycle, will switch with last_remslot */ - - TraceStack *trace_stack; - MarkStack *mark_stack; - - VmEventHandle task_assigned_event; - VmEventHandle task_finished_event; - - void(*task_func)(void*) ; /* current task */ - -}Collector; - -void collector_destruct(GC* gc); -void collector_initialize(GC* gc); -void collector_reset(GC* gc); - -void collector_execute_task(GC* gc, TaskType task_func, Space* space); - -Partial_Reveal_Object* collector_forward_object(Collector* collector, Partial_Reveal_Object* p_obj); - -#endif //#ifndef _COLLECTOR_H_ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#ifndef _COLLECTOR_H_ +#define _COLLECTOR_H_ + +#include "../common/gc_common.h" + +typedef struct Collector{ + /* <-- first couple of fields are overloaded as Allocator */ + void *free; + void *ceiling; + void *alloc_block; + Space* alloc_space; + GC* gc; + VmThreadHandle thread_handle; /* This thread; */ + /* End of Allocator --> */ + + Space* collect_space; + /* collector has remsets to remember those stored during copying */ + RemslotSet* last_cycle_remset; /* remembered in last cycle, used in this cycle as roots */ + RemslotSet* this_cycle_remset; /* remembered in this cycle, will switch with last_remslot */ + + TraceStack *trace_stack; + MarkStack *mark_stack; + + VmEventHandle task_assigned_event; + VmEventHandle task_finished_event; + + void(*task_func)(void*) ; /* current task */ + +}Collector; + +void collector_destruct(GC* gc); +void collector_initialize(GC* gc); +void collector_reset(GC* gc); + +void collector_execute_task(GC* gc, TaskType task_func, Space* space); + +Partial_Reveal_Object* collector_forward_object(Collector* collector, Partial_Reveal_Object* p_obj); + +#endif //#ifndef _COLLECTOR_H_ Index: src/thread/mutator.cpp =================================================================== --- src/thread/mutator.cpp (revision 465167) +++ src/thread/mutator.cpp (working copy) @@ -1,85 +1,79 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#include "mutator.h" -#include "../trace_forward/fspace.h" - -struct GC_Gen; -Space* gc_get_nos(GC_Gen* gc); -void mutator_initialize(GC* gc, void *gc_information) -{ - /* FIXME:: NOTE: gc_info is uncleared */ - Mutator *mutator = (Mutator *) gc_information; - mutator->free = NULL; - mutator->ceiling = NULL; - mutator->curr_alloc_block = NULL; - mutator->alloc_space = gc_get_nos((GC_Gen*)gc); - mutator->gc = gc; - - assert(mutator->remslot == NULL); - mutator->remslot = new RemslotSet(); - mutator->remslot->clear(); - - assert(mutator->remobj == NULL); - mutator->remobj = new RemobjSet(); - mutator->remobj->clear(); - - lock(gc->mutator_list_lock); // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - - mutator->next = (Mutator *)gc->mutator_list; - gc->mutator_list = mutator; - - unlock(gc->mutator_list_lock); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - gc->num_mutators++; - return; -} - -void mutator_destruct(GC* gc, void *gc_information) -{ - - Mutator *mutator = (Mutator *)gc_information; - - lock(gc->mutator_list_lock); // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - - Fspace* fspace = (Fspace*)mutator->alloc_space; - fspace->remslot_sets->push_back(mutator->remslot); - mutator->remslot = NULL; - fspace->remobj_sets->push_back(mutator->remobj); - mutator->remobj = NULL; - - volatile Mutator *temp = gc->mutator_list; - if (temp == mutator) { /* it is at the head of the list */ - gc->mutator_list = temp->next; - } else { - while (temp->next != mutator) { - temp = temp->next; - assert(temp); - } - temp->next = mutator->next; - } - - unlock(gc->mutator_list_lock); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - gc->num_mutators--; - return; -} - - +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#include "mutator.h" +#include "../trace_forward/fspace.h" + +struct GC_Gen; +Space* gc_get_nos(GC_Gen* gc); +void mutator_initialize(GC* gc, void *gc_information) +{ + /* FIXME:: NOTE: gc_info is uncleared */ + Mutator *mutator = (Mutator *) gc_information; + mutator->free = NULL; + mutator->ceiling = NULL; + mutator->alloc_block = NULL; + mutator->alloc_space = gc_get_nos((GC_Gen*)gc); + mutator->gc = gc; + + assert(mutator->remslot == NULL); + mutator->remslot = new RemslotSet(); + mutator->remslot->clear(); + + lock(gc->mutator_list_lock); // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + + mutator->next = (Mutator *)gc->mutator_list; + gc->mutator_list = mutator; + + unlock(gc->mutator_list_lock); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + gc->num_mutators++; + return; +} + +void mutator_destruct(GC* gc, void *gc_information) +{ + + Mutator *mutator = (Mutator *)gc_information; + + lock(gc->mutator_list_lock); // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + + Fspace* fspace = (Fspace*)mutator->alloc_space; + fspace->remslot_sets->push_back(mutator->remslot); + mutator->remslot = NULL; + + volatile Mutator *temp = gc->mutator_list; + if (temp == mutator) { /* it is at the head of the list */ + gc->mutator_list = temp->next; + } else { + while (temp->next != mutator) { + temp = temp->next; + assert(temp); + } + temp->next = mutator->next; + } + + unlock(gc->mutator_list_lock); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + gc->num_mutators--; + return; +} + + Index: src/common/gc_common.cpp =================================================================== --- src/common/gc_common.cpp (revision 465167) +++ src/common/gc_common.cpp (working copy) @@ -88,6 +88,7 @@ return; } +/* NOTE:: Only marking in object header is idempotent */ void mark_scan_heap(Collector* collector) { GC* gc = collector->gc; @@ -102,23 +103,3 @@ return; } - -void gc_update_rootset(GC* gc) -{ - RootSet* root_set = gc->root_set; - /* update refs in root set after moving collection */ - for(unsigned int i=0; i < root_set->size(); i++){ - Partial_Reveal_Object** p_ref = (*root_set)[i]; - Partial_Reveal_Object* p_obj = *p_ref; - assert(p_obj); /* root ref should never by NULL*/ - /* FIXME:: this should be reconsidered: forwarded in vt or obj_info */ - if(!obj_is_forwarded_in_obj_info(p_obj)){ - assert(obj_belongs_to_space(p_obj, gc_get_los((GC_Gen*)gc))); - continue; - } - Partial_Reveal_Object* p_target_obj = get_forwarding_pointer_in_obj_info(p_obj); - *p_ref = p_target_obj; - } - - return; -} \ No newline at end of file Index: src/common/gc_for_vm.cpp =================================================================== --- src/common/gc_for_vm.cpp (revision 465167) +++ src/common/gc_for_vm.cpp (working copy) @@ -21,9 +21,8 @@ #include "vm_threads.h" #include "../gen/gen.h" +#include "interior_pointer.h" -#include "../common/interior_pointer.h" - static GC* p_global_gc = NULL; void gc_init() @@ -51,6 +50,11 @@ p_global_gc->root_set->push_back(p_ref); } +void gc_add_root_set_entry_interior_pointer (void **slot, int offset, Boolean is_pinned) +{ + add_root_set_entry_interior_pointer(slot, offset, is_pinned); +} + /* VM to force GC */ void gc_force_gc() { @@ -109,5 +113,3 @@ unsigned int gc_time_since_last_gc() { assert(0); return 0; } -void gc_add_root_set_entry_interior_pointer (void **slot, int offset, Boolean is_pinned) -{ add_root_set_entry_interior_pointer(slot, offset, is_pinned); } Index: src/common/gc_common.h =================================================================== --- src/common/gc_common.h (revision 465167) +++ src/common/gc_common.h (working copy) @@ -60,11 +60,8 @@ #define BIT_MASK_TO_BITS_PER_WORD ((1<> 1) - typedef void (*TaskType)(void*); #define GC_NUM_ROOTS_HINT 10000 @@ -253,7 +250,7 @@ { gc->root_set->clear(); } -void gc_update_rootset(GC* gc); + void mark_scan_heap(Collector* collector); inline void* gc_heap_base(GC* gc){ return gc->heap_start; } Index: src/common/gc_block.h =================================================================== --- src/common/gc_block.h (revision 0) +++ src/common/gc_block.h (revision 0) @@ -0,0 +1,169 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#ifndef _BLOCK_H_ +#define _BLOCK_H_ + +#include "../common/gc_common.h" + +#define GC_BLOCK_SHIFT_COUNT 15 +#define GC_BLOCK_SIZE_BYTES (1 << GC_BLOCK_SHIFT_COUNT) + +enum Block_Status { + BLOCK_NIL, + BLOCK_FREE, + BLOCK_IN_USE, + BLOCK_USED +}; + +typedef struct Block_Header { + void* base; + void* free; + void* ceiling; + unsigned int block_idx; + unsigned int status; + SlotVector* reloc_table; + Block_Header* next; + unsigned int mark_table[1]; /* entry num == MARKBIT_TABLE_SIZE_WORDS */ +}Block_Header; + +typedef union Block{ + Block_Header header; + unsigned char raw_bytes[GC_BLOCK_SIZE_BYTES]; +}Block; + +#define GC_BLOCK_HEADER_VARS_SIZE_BYTES (unsigned int)&(((Block_Header*)0)->mark_table) + +/* BlockSize - MarkbitTable*32 = HeaderVars + MarkbitTable + => MarkbitTable = (BlockSize - HeaderVars)/33 */ +#define MARKBIT_TABLE_COMPUTE_DIVISOR 33 +/* +1 to round up*/ +#define MARKBIT_TABLE_COMPUTED_SIZE_BYTE ((GC_BLOCK_SIZE_BYTES-GC_BLOCK_HEADER_VARS_SIZE_BYTES)/MARKBIT_TABLE_COMPUTE_DIVISOR + 1) +#define MARKBIT_TABLE_SIZE_WORDS ((MARKBIT_TABLE_COMPUTED_SIZE_BYTE + MASK_OF_BYTES_PER_WORD)&~MASK_OF_BYTES_PER_WORD) +#define MARKBIT_TABLE_SIZE_BYTES (MARKBIT_TABLE_SIZE_WORDS * BYTES_PER_WORD) + +#define GC_BLOCK_HEADER_SIZE_BYTES (MARKBIT_TABLE_SIZE_BYTES + GC_BLOCK_HEADER_VARS_SIZE_BYTES) +#define GC_BLOCK_BODY_SIZE_BYTES (GC_BLOCK_SIZE_BYTES - GC_BLOCK_HEADER_SIZE_BYTES) +#define GC_BLOCK_BODY(block) ((void*)((unsigned int)(block) + GC_BLOCK_HEADER_SIZE_BYTES)) +#define GC_BLOCK_END(block) ((void*)((unsigned int)(block) + GC_BLOCK_SIZE_BYTES)) + +#define GC_BLOCK_LOW_MASK ((unsigned int)(GC_BLOCK_SIZE_BYTES - 1)) +#define GC_BLOCK_HIGH_MASK (~GC_BLOCK_LOW_MASK) +#define GC_BLOCK_HEADER(addr) ((Block_Header *)((unsigned int)(addr) & GC_BLOCK_HIGH_MASK)) +#define GC_BLOCK_INDEX(addr) ((unsigned int)(GC_BLOCK_HEADER(addr)->block_idx)) +#define GC_BLOCK_INDEX_FROM(heap_start, addr) ((unsigned int)(((unsigned int)(addr)-(unsigned int)(heap_start)) >> GC_BLOCK_SHIFT_COUNT)) + +#define ADDRESS_OFFSET_TO_BLOCK_HEADER(addr) ((unsigned int)((unsigned int)addr&GC_BLOCK_LOW_MASK)) +#define ADDRESS_OFFSET_IN_BLOCK_BODY(addr) ((unsigned int)(ADDRESS_OFFSET_TO_BLOCK_HEADER(addr)- GC_BLOCK_HEADER_SIZE_BYTES)) + +#define OBJECT_BIT_INDEX_TO_MARKBIT_TABLE(p_obj) (ADDRESS_OFFSET_IN_BLOCK_BODY(p_obj) >> 2) +#define OBJECT_WORD_INDEX_TO_MARKBIT_TABLE(p_obj) (OBJECT_BIT_INDEX_TO_MARKBIT_TABLE(p_obj) >> BIT_SHIFT_TO_BITS_PER_WORD) +#define OBJECT_WORD_OFFSET_IN_MARKBIT_TABLE(p_obj) (OBJECT_BIT_INDEX_TO_MARKBIT_TABLE(p_obj) & BIT_MASK_TO_BITS_PER_WORD) + +inline Partial_Reveal_Object* block_get_first_marked_object(Block_Header* block, unsigned int* mark_bit_idx) +{ + unsigned int* mark_table = block->mark_table; + unsigned int* table_end = mark_table + MARKBIT_TABLE_SIZE_WORDS; + + unsigned j=0; + unsigned int k=0; + while( (mark_table + j) < table_end){ + unsigned int markbits = *(mark_table+j); + if(!markbits){ j++; continue; } + while(k<32){ + if( !(markbits& (1<mark_table; + unsigned int* table_end = mark_table + MARKBIT_TABLE_SIZE_WORDS; + unsigned int bit_index = *mark_bit_idx; + + unsigned int j = bit_index >> BIT_SHIFT_TO_BITS_PER_WORD; + unsigned int k = (bit_index & BIT_MASK_TO_BITS_PER_WORD) + 1; + + while( (mark_table + j) < table_end){ + unsigned int markbits = *(mark_table+j); + if(!markbits){ j++; continue; } + while(k<32){ + if( !(markbits& (1<mark_table; + memset(mark_table, 0, MARKBIT_TABLE_SIZE_BYTES); + return; +} + +inline void block_clear_markbits(Block_Header* block) +{ + unsigned int* mark_table = block->mark_table; + unsigned int* table_end = mark_table + MARKBIT_TABLE_SIZE_WORDS; + + unsigned j=0; + while( (mark_table + j) < table_end){ + unsigned int markbits = *(mark_table+j); + if(!markbits){ j++; continue; } + unsigned int k=0; + while(k<32){ + if( !(markbits& (1< */ + Block* blocks; Fspace *nos; Mspace *mos; Lspace *los; @@ -94,6 +93,7 @@ lspace_free_memory_size(gc->los); } void gc_gen_reclaim_heap(GC_Gen* gc, unsigned int cause); +void gc_gen_update_repointed_refs(Collector* collector); ///////////////////////////////////////////////////////////////////////////////////////// @@ -128,9 +128,9 @@ return (Space*)((GC_Gen*)gc)->los; } -void* mos_alloc(unsigned size, Alloc_Context *alloc_ctx); -void* nos_alloc(unsigned size, Alloc_Context *alloc_ctx); -void* los_alloc(unsigned size, Alloc_Context *alloc_ctx); +void* mos_alloc(unsigned size, Allocator *allocator); +void* nos_alloc(unsigned size, Allocator *allocator); +void* los_alloc(unsigned size, Allocator *allocator); Space* gc_get_nos(GC_Gen* gc); Space* gc_get_mos(GC_Gen* gc); Space* gc_get_los(GC_Gen* gc); Index: src/gen/gc_for_barrier.cpp =================================================================== --- src/gen/gc_for_barrier.cpp (revision 465167) +++ src/gen/gc_for_barrier.cpp (working copy) @@ -24,59 +24,84 @@ /* All the write barrier interfaces need cleanup */ +static Boolean NEED_BARRIER = TRUE; + Boolean gc_requires_barriers() -{ return 1; } +{ return NEED_BARRIER; } /* The implementations are only temporary */ -static void gc_write_barrier_generic(Managed_Object_Handle p_obj_holding_ref, Managed_Object_Handle *p_slot, - Managed_Object_Handle p_target, unsigned int kind) +static void gc_slot_write_barrier(Managed_Object_Handle *p_slot, + Managed_Object_Handle p_target) { Mutator *mutator = (Mutator *)vm_get_gc_thread_local(); GC_Gen* gc = (GC_Gen*)mutator->gc; - if(kind == WRITE_BARRIER_SLOT ){ - if( address_belongs_to_nursery((void *)p_target, gc) && - !address_belongs_to_nursery((void *)p_slot, gc)) - { - mutator->remslot->push_back((Partial_Reveal_Object **)p_slot); - } - }else if( kind == WRITE_BARRIER_OBJECT ){ - if( !address_belongs_to_nursery((void *)p_obj_holding_ref, gc) ) { - mutator->remobj->push_back((Partial_Reveal_Object *)p_obj_holding_ref); - } - }else{ - assert(kind == WRITE_BARRIER_UPDATE ); - *p_slot = p_target; - if( address_belongs_to_nursery((void *)p_target, gc) && - !address_belongs_to_nursery((void *)p_slot, gc)) - { - mutator->remslot->push_back((Partial_Reveal_Object **)p_slot); - } + if( address_belongs_to_nursery((void *)p_target, gc) && + !address_belongs_to_nursery((void *)p_slot, gc)) + { + mutator->remslot->push_back((Partial_Reveal_Object **)p_slot); } } -/* temporary write barriers, need reconsidering */ -void gc_write_barrier(Managed_Object_Handle p_obj_holding_ref) +static void gc_object_write_barrier(Managed_Object_Handle p_object) { - gc_write_barrier_generic(p_obj_holding_ref, NULL, NULL, WRITE_BARRIER_OBJECT); + Mutator *mutator = (Mutator *)vm_get_gc_thread_local(); + GC_Gen* gc = (GC_Gen*)mutator->gc; + if( !address_belongs_to_nursery((void *)p_object, gc)) return; + + Partial_Reveal_Object **p_slot; + /* scan array object */ + if (object_is_array((Partial_Reveal_Object*)p_object)) { + Partial_Reveal_Object* array = (Partial_Reveal_Object*)p_object; + assert(!obj_is_primitive_array(array)); + + int32 array_length = vector_get_length((Vector_Handle) array); + for (int i = 0; i < array_length; i++) { + p_slot = (Partial_Reveal_Object **)vector_get_element_address_ref((Vector_Handle) array, i); + if( *p_slot != NULL && address_belongs_to_nursery((void *)*p_slot, gc)){ + mutator->remslot->push_back(p_slot); + } + } + return; + } + + /* scan non-array object */ + Partial_Reveal_Object* p_obj = (Partial_Reveal_Object*)p_object; + int *offset_scanner = init_object_scanner(p_obj); + while (true) { + p_slot = (Partial_Reveal_Object**)offset_get_ref(offset_scanner, p_obj); + if (p_slot == NULL) break; + if( address_belongs_to_nursery((void *)*p_slot, gc)){ + mutator->remslot->push_back(p_slot); + } + offset_scanner = offset_next_ref(offset_scanner); + } + + return; } -/* for array copy and object clone */ -void gc_heap_wrote_object (Managed_Object_Handle p_obj_holding_ref) +void gc_heap_wrote_object (Managed_Object_Handle p_obj_written) { - gc_write_barrier_generic(p_obj_holding_ref, NULL, NULL, WRITE_BARRIER_OBJECT); + if( !NEED_BARRIER ) return; + if( object_has_slots((Partial_Reveal_Object*)p_obj_written)){ + /* for array copy and object clone */ + gc_object_write_barrier(p_obj_written); + } } /* The following routines were supposed to be the only way to alter any value in gc heap. */ void gc_heap_write_ref (Managed_Object_Handle p_obj_holding_ref, unsigned offset, Managed_Object_Handle p_target) { assert(0); } +/* FIXME:: this is not the right interface for write barrier */ void gc_heap_slot_write_ref (Managed_Object_Handle p_obj_holding_ref,Managed_Object_Handle *p_slot, Managed_Object_Handle p_target) { - gc_write_barrier_generic(NULL, p_slot, p_target, WRITE_BARRIER_UPDATE); + *p_slot = p_target; + if( !NEED_BARRIER ) return; + gc_slot_write_barrier(p_slot, p_target); } /* this is used for global object update, e.g., strings. Since globals are roots, no barrier here */ void gc_heap_write_global_slot(Managed_Object_Handle *p_slot,Managed_Object_Handle p_target) { *p_slot = p_target; -} \ No newline at end of file +} Index: src/gen/gen.cpp =================================================================== --- src/gen/gen.cpp (revision 465167) +++ src/gen/gen.cpp (working copy) @@ -27,7 +27,7 @@ /* heap size limit is not interesting. only for manual tuning purpose */ unsigned int min_heap_size_bytes = 32 * MB; -unsigned int max_heap_size_bytes = 64 * MB; +unsigned int max_heap_size_bytes = 128 * MB; /* fspace size limit is not interesting. only for manual tuning purpose */ unsigned int min_nos_size_bytes = 2 * MB; @@ -76,17 +76,18 @@ gc_gen->reserved_heap_size = max_heap_size; gc_gen->heap_start = reserved_base; gc_gen->heap_end = (void*)((unsigned int)reserved_base + max_heap_size); + gc_gen->blocks = (Block*)reserved_base; gc_gen->num_collections = 0; /* heuristic nos + mos + LOS */ - unsigned int nos_size = max_heap_size >> 4; + unsigned int nos_size = max_heap_size >> 2; assert(nos_size > min_nos_size_bytes); gc_nos_initialize(gc_gen, reserved_base, nos_size); unsigned int mos_size = max_heap_size >> 1; reserved_base = (void*)((unsigned int)reserved_base + nos_size); gc_mos_initialize(gc_gen, reserved_base, mos_size); - + unsigned int los_size = max_heap_size >> 2; reserved_base = (void*)((unsigned int)gc_gen->heap_end - los_size); gc_los_initialize(gc_gen, reserved_base, los_size); @@ -137,9 +138,9 @@ return mspace_free_memory_size(gc->mos) < fspace_used_memory_size(gc->nos); } -void* mos_alloc(unsigned size, Alloc_Context *alloc_ctx){return mspace_alloc(size, alloc_ctx);} -void* nos_alloc(unsigned size, Alloc_Context *alloc_ctx){return fspace_alloc(size, alloc_ctx);} -void* los_alloc(unsigned size, Alloc_Context *alloc_ctx){return lspace_alloc(size, alloc_ctx);} +void* mos_alloc(unsigned size, Allocator *allocator){return mspace_alloc(size, allocator);} +void* nos_alloc(unsigned size, Allocator *allocator){return fspace_alloc(size, allocator);} +void* los_alloc(unsigned size, Allocator *allocator){return lspace_alloc(size, allocator);} Space* gc_get_nos(GC_Gen* gc){ return (Space*)gc->nos;} Space* gc_get_mos(GC_Gen* gc){ return (Space*)gc->mos;} Space* gc_get_los(GC_Gen* gc){ return (Space*)gc->los;} @@ -148,10 +149,60 @@ void gc_set_los(GC_Gen* gc, Space* los){ gc->los = (Lspace*)los;} unsigned int gc_get_processor_num(GC_Gen* gc){ return gc->_num_processors;} +static void gc_gen_update_rootset(GC* gc) +{ + RootSet* root_set = gc->root_set; + /* update refs in root set after moving collection */ + for(unsigned int i=0; i < root_set->size(); i++){ + Partial_Reveal_Object** p_ref = (*root_set)[i]; + Partial_Reveal_Object* p_obj = *p_ref; + assert(p_obj); /* root ref should never by NULL*/ + /* FIXME:: this should be reconsidered: forwarded in vt or obj_info */ + if(!obj_is_forwarded_in_obj_info(p_obj)){ + /* if an obj is not moved, it must be in LOS or otherwise in MOS for MINOR_COLLECTION */ +#ifdef _DEBUG + if( gc->collect_kind == MINOR_COLLECTION ) + assert( !obj_belongs_to_space(p_obj, gc_get_nos((GC_Gen*)gc)) ); + else + assert( obj_belongs_to_space(p_obj, gc_get_los((GC_Gen*)gc)) ); +#endif + continue; + } + Partial_Reveal_Object* p_target_obj = get_forwarding_pointer_in_obj_info(p_obj); + *p_ref = p_target_obj; + } + + return; +} + +void update_rootset_interior_pointer(); + +void gc_gen_update_repointed_refs(Collector* collector) +{ + GC_Gen* gc = (GC_Gen*)collector->gc; + Space* space; + space = gc_get_nos(gc); space->update_reloc_func(space); + space = gc_get_mos(gc); space->update_reloc_func(space); + space = gc_get_los(gc); space->update_reloc_func(space); + + gc_gen_update_rootset((GC*)gc); + update_rootset_interior_pointer(); + + return; +} + void gc_preprocess_collector(Collector *collector) { + /* for MAJOR_COLLECTION, all the remsets are useless */ GC_Gen* gc = (GC_Gen*)collector->gc; - + if( gc->collect_kind == MAJOR_COLLECTION ){ + collector->last_cycle_remset->clear(); + return; + } + + Fspace* fspace = (Fspace*)gc_get_nos(gc); + fspace->remslot_sets->push_back(collector->last_cycle_remset); + /* this_cycle_remset is ready to be used */ assert(collector->this_cycle_remset->empty()); @@ -160,11 +211,12 @@ void gc_postprocess_collector(Collector *collector) { + /* for MAJOR_COLLECTION we do nothing */ GC_Gen* gc = (GC_Gen*)collector->gc; + if( gc->collect_kind == MAJOR_COLLECTION ) + return; /* for MINOR_COLLECTION */ - Fspace* fspace = (Fspace*)gc_get_nos(gc); - /* switch its remsets, this_cycle_remset data kept in space->remslot_sets */ /* last_cycle_remset was in space->remslot_sets and cleared during collection */ assert(collector->last_cycle_remset->empty()); @@ -173,32 +225,32 @@ collector->this_cycle_remset = collector->last_cycle_remset; collector->last_cycle_remset = temp_set; - fspace->remslot_sets->push_back(collector->last_cycle_remset); - return; } void gc_preprocess_mutator(GC_Gen* gc) -{ +{ Mutator *mutator = gc->mutator_list; Fspace* fspace = (Fspace*)mutator->alloc_space; - + /* for MAJOR_COLLECTION, all the remsets are useless */ while (mutator) { - fspace->remslot_sets->push_back(mutator->remslot); - fspace->remobj_sets->push_back(mutator->remobj); + if(gc->collect_kind == MAJOR_COLLECTION){ + mutator->remslot->clear(); + }else{ + fspace->remslot_sets->push_back(mutator->remslot); + } mutator = mutator->next; } return; -} +} /////////FIXME::: need clear space remsets void gc_postprocess_mutator(GC_Gen* gc) { Mutator *mutator = gc->mutator_list; while (mutator) { - assert(mutator->remobj->empty()); assert(mutator->remslot->empty()); - alloc_context_reset((Alloc_Context*)mutator); + alloc_context_reset((Allocator*)mutator); mutator = mutator->next; } @@ -209,7 +261,7 @@ { if(major_collection_needed(gc) || cause== GC_CAUSE_LOS_IS_FULL) return MAJOR_COLLECTION; - + return MINOR_COLLECTION; } @@ -227,9 +279,27 @@ if(verify_live_heap) gc_verify_heap((GC*)gc, TRUE); - if(gc->collect_kind == MINOR_COLLECTION) - fspace_collection(gc->nos); - else{ + if(gc->collect_kind == MINOR_COLLECTION){ + if( gc_requires_barriers()) /* normal gen gc nos collection */ + fspace_collection(gc->nos); + else{ /* copy nos to mos for non-gen gc */ + /* we don't move mos objects in MINOR_COLLECTION. This is true for both + gen or non-gen collections, but only meaningful for non-gen GC, because + non-gen GC need mark the heap in order to find the refs from mos/los to nos. + This can save lots of reloc table space for slots having ref pointing to mos. + For gen GC, MINOR_COLLECTION doesn't really mark the heap. It has remsets that + have all the refs from mos/los to nos, which are actually the same thing as reloc table */ + gc->mos->move_object = FALSE; + fspace_collection(gc->nos); + gc->mos->move_object = TRUE; + + /* these are only needed for non-gen MINOR_COLLECTION, because + both mos and los will be collected (and reset) in MAJOR_COLLECTION */ + reset_mspace_after_copy_nursery(gc->mos); + reset_lspace_after_copy_nursery(gc->los); + } + }else{ + /* process mos and nos together in one compaction */ mspace_collection(gc->mos); /* fspace collection is included */ lspace_collection(gc->los); } Index: src/mark_sweep/lspace.cpp =================================================================== --- src/mark_sweep/lspace.cpp (revision 465167) +++ src/mark_sweep/lspace.cpp (working copy) @@ -1,121 +1,129 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#include "lspace.h" - -void* los_boundary = NULL; -struct GC_Gen; -Space* gc_get_los(GC_Gen* gc); -void gc_set_los(GC_Gen* gc, Space* lspace); -void* lspace_alloc(unsigned int size, Alloc_Context *alloc_ctx) -{ - Lspace* lspace = (Lspace*)gc_get_los((GC_Gen*)alloc_ctx->gc); - - unsigned int old_free = (unsigned int)lspace->alloc_free; - unsigned int new_free = old_free + size; - - while(new_free <= (unsigned int)lspace->heap_end){ - unsigned int temp = atomic_cas32((volatile unsigned int *)&lspace->alloc_free, new_free, old_free); - if (temp != old_free) { - old_free = (unsigned int)lspace->alloc_free; - new_free = old_free + size; - continue; - } - /* successfully allocate an object */ - Partial_Reveal_Object* p_return_object = (Partial_Reveal_Object*)old_free; - lspace->alloc_free = (void*)new_free; - - /* TODO: should moved to better location */ - memset(p_return_object, 0, size); - - return (void*)old_free; - } - - /* FIXME:: trigger collection */ - assert(0); - return NULL; - -} - -void lspace_initialize(GC* gc, void* start, unsigned int lspace_size) -{ - Lspace* lspace = (Lspace*)STD_MALLOC( sizeof(Lspace)); - assert(lspace); - memset(lspace, 0, sizeof(Lspace)); - - void* reserved_base = start; - unsigned int committed_size = lspace_size >> 1; - int status = port_vmem_commit(&reserved_base, committed_size, gc->allocated_memory); - assert(status == APR_SUCCESS && reserved_base == start); - - memset(reserved_base, 0, committed_size); - lspace->committed_heap_size = committed_size; - lspace->reserved_heap_size = lspace_size - committed_size; - lspace->heap_start = reserved_base; - lspace->heap_end = (void *)((unsigned int)reserved_base + committed_size); - lspace->alloc_free = reserved_base; - - unsigned int num_bits = lspace_size >> BIT_SHIFT_TO_KILO; - unsigned int num_words = (num_bits >> BIT_SHIFT_TO_BITS_PER_WORD)+1; - lspace->mark_table = (unsigned int*)STD_MALLOC( num_words*BYTES_PER_WORD ); - memset(lspace->mark_table, 0, num_words*BYTES_PER_WORD); - - lspace->reloc_table = new SlotVector(); - lspace->mark_object_func = lspace_mark_object; - lspace->save_reloc_func = lspace_save_reloc; - lspace->update_reloc_func = lspace_update_reloc; - - lspace->move_object = FALSE; - lspace->gc = gc; - gc_set_los((GC_Gen*)gc, (Space*)lspace); - - los_boundary = start; - - return; -} - -void lspace_destruct(Lspace* lspace) -{ - //FIXME:: decommit lspace space - STD_FREE(lspace->mark_table); - STD_FREE(lspace); - lspace = NULL; - return; -} - -void lspace_collection(Lspace* lspace) -{ - /* FIXME:: collection */ - unsigned int used_size = (unsigned int)lspace->alloc_free - (unsigned int)lspace->heap_start; - memset(lspace->mark_table, 0, (used_size>>BIT_SHIFT_TO_KILO)>>BIT_SHIFT_TO_BITS_PER_BYTE ); - - return; -} - -Boolean lspace_mark_object(Lspace* lspace, Partial_Reveal_Object* p_obj) -{ - assert( obj_belongs_to_space(p_obj, (Space*)lspace)); - unsigned int word_index = OBJECT_WORD_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj); - unsigned int bit_offset_in_word = OBJECT_WORD_OFFSET_IN_LSPACE_MARKBIT_TABLE(lspace, p_obj); - - unsigned int* p_markbits = &(lspace->mark_table[word_index]); +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#include "lspace.h" + +void* los_boundary = NULL; +struct GC_Gen; +Space* gc_get_los(GC_Gen* gc); +void gc_set_los(GC_Gen* gc, Space* lspace); +void* lspace_alloc(unsigned int size, Allocator *allocator) +{ + Lspace* lspace = (Lspace*)gc_get_los((GC_Gen*)allocator->gc); + + unsigned int old_free = (unsigned int)lspace->alloc_free; + unsigned int new_free = old_free + size; + + while(new_free <= (unsigned int)lspace->heap_end){ + unsigned int temp = atomic_cas32((volatile unsigned int *)&lspace->alloc_free, new_free, old_free); + if (temp != old_free) { + old_free = (unsigned int)lspace->alloc_free; + new_free = old_free + size; + continue; + } + /* successfully allocate an object */ + Partial_Reveal_Object* p_return_object = (Partial_Reveal_Object*)old_free; + lspace->alloc_free = (void*)new_free; + + /* TODO: should moved to better location */ + memset(p_return_object, 0, size); + + return (void*)old_free; + } + + /* FIXME:: trigger collection */ + assert(0); + return NULL; + +} + +void lspace_initialize(GC* gc, void* start, unsigned int lspace_size) +{ + Lspace* lspace = (Lspace*)STD_MALLOC( sizeof(Lspace)); + assert(lspace); + memset(lspace, 0, sizeof(Lspace)); + + void* reserved_base = start; + unsigned int committed_size = lspace_size >> 1; + int status = port_vmem_commit(&reserved_base, committed_size, gc->allocated_memory); + assert(status == APR_SUCCESS && reserved_base == start); + + memset(reserved_base, 0, committed_size); + lspace->committed_heap_size = committed_size; + lspace->reserved_heap_size = lspace_size - committed_size; + lspace->heap_start = reserved_base; + lspace->heap_end = (void *)((unsigned int)reserved_base + committed_size); + lspace->alloc_free = reserved_base; + + unsigned int num_bits = lspace_size >> BIT_SHIFT_TO_KILO; + unsigned int num_words = (num_bits >> BIT_SHIFT_TO_BITS_PER_WORD)+1; + lspace->mark_table = (unsigned int*)STD_MALLOC( num_words*BYTES_PER_WORD ); + memset(lspace->mark_table, 0, num_words*BYTES_PER_WORD); + + lspace->reloc_table = new SlotVector(); + lspace->mark_object_func = lspace_mark_object; + lspace->save_reloc_func = lspace_save_reloc; + lspace->update_reloc_func = lspace_update_reloc; + + lspace->move_object = FALSE; + lspace->gc = gc; + gc_set_los((GC_Gen*)gc, (Space*)lspace); + + los_boundary = start; + + return; +} + +void lspace_destruct(Lspace* lspace) +{ + //FIXME:: decommit lspace space + STD_FREE(lspace->mark_table); + STD_FREE(lspace); + lspace = NULL; + return; +} + +void lspace_collection(Lspace* lspace) +{ + /* FIXME:: collection */ + unsigned int used_size = (unsigned int)lspace->alloc_free - (unsigned int)lspace->heap_start; + memset(lspace->mark_table, 0, (used_size>>BIT_SHIFT_TO_KILO)>>BIT_SHIFT_TO_BITS_PER_BYTE ); + + return; +} + +void reset_lspace_after_copy_nursery(Lspace* lspace) +{ + unsigned int used_size = (unsigned int)lspace->alloc_free - (unsigned int)lspace->heap_start; + memset(lspace->mark_table, 0, (used_size>>BIT_SHIFT_TO_KILO)>>BIT_SHIFT_TO_BITS_PER_BYTE ); + return; +} + + +Boolean lspace_mark_object(Lspace* lspace, Partial_Reveal_Object* p_obj) +{ + assert( obj_belongs_to_space(p_obj, (Space*)lspace)); + unsigned int word_index = OBJECT_WORD_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj); + unsigned int bit_offset_in_word = OBJECT_WORD_OFFSET_IN_LSPACE_MARKBIT_TABLE(lspace, p_obj); + + unsigned int* p_markbits = &(lspace->mark_table[word_index]); unsigned int word_mask = (1<reloc_table->push_back(p_ref); + + return TRUE; } - -void lspace_update_reloc(Lspace* lspace) -{ - SlotVector* reloc_table; - - reloc_table = lspace->reloc_table; - for(unsigned int j=0; j < reloc_table->size(); j++){ - Partial_Reveal_Object** p_ref = (*reloc_table)[j]; - Partial_Reveal_Object* p_target_obj = get_forwarding_pointer_in_obj_info(*p_ref); - *p_ref = p_target_obj; - } - reloc_table->clear(); - return; -} + +void lspace_save_reloc(Lspace* lspace, Partial_Reveal_Object** p_ref) +{ + lspace->reloc_table->push_back(p_ref); +} + +void lspace_update_reloc(Lspace* lspace) +{ + SlotVector* reloc_table; + + reloc_table = lspace->reloc_table; + for(unsigned int j=0; j < reloc_table->size(); j++){ + Partial_Reveal_Object** p_ref = (*reloc_table)[j]; + Partial_Reveal_Object* p_target_obj = get_forwarding_pointer_in_obj_info(*p_ref); + *p_ref = p_target_obj; + } + reloc_table->clear(); + return; +} Index: src/mark_sweep/lspace.h =================================================================== --- src/mark_sweep/lspace.h (revision 465167) +++ src/mark_sweep/lspace.h (working copy) @@ -1,77 +1,79 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Xiao-Feng Li, 2006/10/05 - */ - -#ifndef _LSPACE_H_ -#define _LSPACE_H_ - -#include "../common/gc_common.h" -#include "../thread/thread_alloc.h" - -typedef struct Lspace{ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Xiao-Feng Li, 2006/10/05 + */ + +#ifndef _LSPACE_H_ +#define _LSPACE_H_ + +#include "../common/gc_common.h" +#include "../thread/thread_alloc.h" + +typedef struct Lspace{ /* <-- first couple of fields are overloadded as Space */ void* heap_start; void* heap_end; unsigned int reserved_heap_size; unsigned int committed_heap_size; - unsigned int num_collections; - GC* gc; - Boolean move_object; + unsigned int num_collections; + GC* gc; + Boolean move_object; Boolean (*mark_object_func)(Lspace* space, Partial_Reveal_Object* p_obj); void (*save_reloc_func)(Lspace* space, Partial_Reveal_Object** p_ref); - void (*update_reloc_func)(Lspace* space); - /* END of Space --> */ - - void* alloc_free; - - unsigned int* mark_table; - + void (*update_reloc_func)(Lspace* space); + /* END of Space --> */ + + void* alloc_free; + + unsigned int* mark_table; + /* support other space moving collection */ - SlotVector* reloc_table; - -}Lspace; - -void lspace_initialize(GC* gc, void* reserved_base, unsigned int lspace_size); -void lspace_destruct(Lspace* lspace); -Managed_Object_Handle lspace_alloc(unsigned int size, Alloc_Context* alloc_ctx); -void lspace_collection(Lspace* lspace); - -inline unsigned int lspace_free_memory_size(Lspace* lspace){ /* FIXME:: */ return 0; } - -/* The assumption is the offset below is always aligned at word size, because both numbers are aligned */ -#define ADDRESS_OFFSET_IN_LSPACE_BODY(lspace, p_obj) ((unsigned int)p_obj - (unsigned int)space_heap_start((Space*)lspace)) -#define OBJECT_BIT_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj) (ADDRESS_OFFSET_IN_LSPACE_BODY(lspace, p_obj) >> BIT_SHIFT_TO_KILO) -#define OBJECT_WORD_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj) (OBJECT_BIT_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj) >> BIT_SHIFT_TO_BITS_PER_WORD) -#define OBJECT_WORD_OFFSET_IN_LSPACE_MARKBIT_TABLE(lspace, p_obj) (OBJECT_BIT_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj) & BIT_MASK_TO_BITS_PER_WORD) - -inline Boolean lspace_object_is_marked(Lspace* lspace, Partial_Reveal_Object* p_obj) -{ - assert( obj_belongs_to_space(p_obj, (Space*)lspace)); - unsigned int word_index = OBJECT_WORD_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj); - unsigned int bit_offset_in_word = OBJECT_WORD_OFFSET_IN_LSPACE_MARKBIT_TABLE(lspace, p_obj); - - unsigned int markbits = lspace->mark_table[word_index]; - return markbits & (1<> BIT_SHIFT_TO_KILO) +#define OBJECT_WORD_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj) (OBJECT_BIT_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj) >> BIT_SHIFT_TO_BITS_PER_WORD) +#define OBJECT_WORD_OFFSET_IN_LSPACE_MARKBIT_TABLE(lspace, p_obj) (OBJECT_BIT_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj) & BIT_MASK_TO_BITS_PER_WORD) + +inline Boolean lspace_object_is_marked(Lspace* lspace, Partial_Reveal_Object* p_obj) +{ + assert( obj_belongs_to_space(p_obj, (Space*)lspace)); + unsigned int word_index = OBJECT_WORD_INDEX_TO_LSPACE_MARKBIT_TABLE(lspace, p_obj); + unsigned int bit_offset_in_word = OBJECT_WORD_OFFSET_IN_LSPACE_MARKBIT_TABLE(lspace, p_obj); + + unsigned int markbits = lspace->mark_table[word_index]; + return markbits & (1<