blob: 10d2216b691339666be64df7a07f611638945dde [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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/25
*/
#ifndef _GC_METADATA_H_
#define _GC_METADATA_H_
#include "gc_common.h"
#include "../utils/vector_block.h"
#include "../utils/sync_pool.h"
#include "../thread/collector.h"
#include "../thread/mutator.h"
#define GC_METADATA_SEGMENT_NUM 256
typedef struct GC_Metadata{
void *segments[GC_METADATA_SEGMENT_NUM]; /* address array of malloced segments for free pool */
unsigned int num_alloc_segs; /* allocated segment number */
SpinLock alloc_lock;
Pool* free_task_pool; /* list of free buffers for mark tasks */
Pool* mark_task_pool; /* list of mark tasks */
/* FIXME:: the mutator remset pool can be merged with the rootset pool*/
Pool* free_set_pool; /* list of free buffers for rootsets remsets */
Pool* gc_rootset_pool; /* list of root sets for enumeration */
Pool* gc_uncompressed_rootset_pool; /* list of uncompressed root sets for enumeration */
Pool* mutator_remset_pool; /* list of remsets generated by app during execution */
Pool* collector_remset_pool; /* list of remsets generated by gc during collection */
Pool* collector_repset_pool; /* list of repointed ref slot sets */
Pool* weakroot_pool; /* list of short weak roots */
#ifdef USE_32BITS_HASHCODE
Pool* collector_hashcode_pool;
#endif
Pool* gc_dirty_set_pool;
}GC_Metadata;
extern GC_Metadata gc_metadata;
void gc_metadata_initialize(GC* gc);
void gc_metadata_destruct(GC* gc);
void gc_metadata_verify(GC* gc, Boolean is_before_gc);
void gc_set_rootset(GC* gc);
void gc_reset_rootset(GC* gc);
void gc_clear_rootset(GC* gc);
void gc_fix_rootset(Collector* collector, Boolean double_fix);
void gc_clear_remset(GC* gc);
void gc_prepare_dirty_set(GC* gc);
void gc_copy_local_dirty_set_to_global(GC *gc);
void gc_reset_dirty_set(GC* gc);
void gc_clear_dirty_set(GC* gc);
void gc_identify_dead_weak_roots(GC *gc);
void gc_update_weak_roots(GC *gc, Boolean double_fix);
void gc_reset_collectors_rem_set(GC *gc);
inline void gc_task_pool_clear(Pool* task_pool)
{
Vector_Block* task = pool_get_entry(task_pool);
while(task){
vector_stack_clear(task);
pool_put_entry(gc_metadata.free_task_pool, task);
task = pool_get_entry(task_pool);
}
return;
}
inline void gc_set_pool_clear(Pool* set_pool)
{
Vector_Block* set = pool_get_entry(set_pool);
while(set){
vector_block_clear(set);
pool_put_entry(gc_metadata.free_set_pool, set);
set = pool_get_entry(set_pool);
}
return;
}
Vector_Block* gc_metadata_extend(Pool* pool);
inline Vector_Block *free_set_pool_get_entry(GC_Metadata *metadata)
{
Vector_Block *block = pool_get_entry(metadata->free_set_pool);
while(!block)
block = gc_metadata_extend(metadata->free_set_pool);
assert(vector_block_is_empty(block));
return block;
}
void free_set_pool_put_entry(Vector_Block* block, GC_Metadata *metadata);
inline Vector_Block *free_task_pool_get_entry(GC_Metadata *metadata)
{
Vector_Block *block = pool_get_entry(metadata->free_task_pool);
while(!block)
block = gc_metadata_extend(metadata->free_task_pool);
assert(vector_block_is_empty(block));
return block;
}
inline void mutator_remset_add_entry(Mutator* mutator, REF* p_ref)
{
assert( p_ref >= gc_heap_base_address() && p_ref < gc_heap_ceiling_address());
Vector_Block* root_set = mutator->rem_set;
vector_block_add_entry(root_set, (POINTER_SIZE_INT)p_ref);
if( !vector_block_is_full(root_set)) return;
pool_put_entry(gc_metadata.mutator_remset_pool, root_set);
mutator->rem_set = free_set_pool_get_entry(&gc_metadata);
assert(mutator->rem_set);
}
inline void mutator_dirtyset_add_entry(Mutator* mutator, Partial_Reveal_Object* p_obj)
{
Vector_Block* dirty_set = mutator->dirty_set;
mutator->dirty_obj_slot_num++;
vector_block_add_entry(dirty_set, (POINTER_SIZE_INT)p_obj);
if( !vector_block_is_full(dirty_set) ) {
return;
}
lock(mutator->dirty_set_lock);
if( vector_block_is_empty(dirty_set) ) {
vector_block_clear(dirty_set);
unlock(mutator->dirty_set_lock);
return;
}
pool_put_entry(gc_metadata.gc_dirty_set_pool, dirty_set);
mutator->dirty_set = free_set_pool_get_entry(&gc_metadata);
unlock(mutator->dirty_set_lock);
}
inline void collector_repset_add_entry(Collector* collector, Partial_Reveal_Object** p_ref)
{
// assert( p_ref >= gc_heap_base_address() && p_ref < gc_heap_ceiling_address());
Vector_Block* root_set = collector->rep_set;
vector_block_add_entry(root_set, (POINTER_SIZE_INT)p_ref);
if( !vector_block_is_full(root_set)) return;
pool_put_entry(gc_metadata.collector_repset_pool, root_set);
collector->rep_set = free_set_pool_get_entry(&gc_metadata);
assert(collector->rep_set);
}
inline void collector_remset_add_entry(Collector* collector, Partial_Reveal_Object** p_ref)
{
//assert( p_ref >= gc_heap_base_address() && p_ref < gc_heap_ceiling_address());
Vector_Block* root_set = collector->rem_set;
vector_block_add_entry(root_set, (POINTER_SIZE_INT)p_ref);
if( !vector_block_is_full(root_set)) return;
pool_put_entry(gc_metadata.collector_remset_pool, root_set);
collector->rem_set = free_set_pool_get_entry(&gc_metadata);
assert(collector->rem_set);
}
#ifdef USE_32BITS_HASHCODE
inline void collector_hashcodeset_add_entry(Collector* collector, Partial_Reveal_Object** p_ref)
{
Vector_Block* hashcode_set = collector->hashcode_set;
vector_block_add_entry(hashcode_set, (POINTER_SIZE_INT) p_ref);
if(!vector_block_is_full(hashcode_set)) return;
pool_put_entry(gc_metadata.collector_hashcode_pool, hashcode_set);
collector->hashcode_set = free_set_pool_get_entry(&gc_metadata);
assert(collector->hashcode_set);
}
#endif
FORCE_INLINE void collector_tracestack_push(Collector* collector, void* p_task)
{
/* we don't have assert as others because p_task is a p_obj for marking,
or a p_ref for trace forwarding. The latter can be a root set pointer */
Vector_Block* trace_task = (Vector_Block*)collector->trace_stack;
vector_stack_push(trace_task, (POINTER_SIZE_INT)p_task);
if( !vector_stack_is_full(trace_task)) return;
pool_put_entry(gc_metadata.mark_task_pool, trace_task);
collector->trace_stack = free_task_pool_get_entry(&gc_metadata);
assert(collector->trace_stack);
}
inline void gc_weak_rootset_add_entry(GC* gc, Partial_Reveal_Object** p_ref, Boolean is_short_weak)
{
//assert(is_short_weak == FALSE); //Currently no need for short_weak_roots
assert( p_ref < gc_heap_base_address() || p_ref >= gc_heap_ceiling_address());
Vector_Block* weakroot_set = gc->weakroot_set;
vector_block_add_entry(weakroot_set, (POINTER_SIZE_INT)p_ref);
if( !vector_block_is_full(weakroot_set)) return;
pool_put_entry(gc_metadata.weakroot_pool, weakroot_set);
gc->weakroot_set = free_set_pool_get_entry(&gc_metadata);
assert(gc->weakroot_set);
}
extern unsigned int rootset_type;
enum ROOTSET_TYPE{
ROOTSET_IS_OBJ = 0x01,
ROOTSET_IS_REF = 0x02
};
inline void gc_set_rootset_type(unsigned int rs_type)
{
rootset_type = rs_type;
}
#ifdef COMPRESS_REFERENCE
inline void gc_rootset_add_entry(GC* gc, Partial_Reveal_Object** p_ref)
{
assert( p_ref < gc_heap_base(gc) || p_ref >= gc_heap_ceiling(gc));
GC_Metadata *metadata = gc->metadata;
Vector_Block *uncompressed_root_set = gc->uncompressed_root_set;
assert(uncompressed_root_set);
Partial_Reveal_Object *p_obj = *p_ref;
REF ref = obj_ptr_to_ref(p_obj);
/* construct an Uncompressed_Root */
vector_block_add_entry(uncompressed_root_set, (POINTER_SIZE_INT)p_ref);
assert(!vector_block_is_full(uncompressed_root_set));
if(rootset_type == ROOTSET_IS_REF)
vector_block_add_entry(uncompressed_root_set, (POINTER_SIZE_INT)ref);
else if(rootset_type == ROOTSET_IS_OBJ)
vector_block_add_entry(uncompressed_root_set, (POINTER_SIZE_INT)p_obj);
if(!vector_block_is_full(uncompressed_root_set)) return;
pool_put_entry(metadata->gc_uncompressed_rootset_pool, uncompressed_root_set);
gc->uncompressed_root_set = free_set_pool_get_entry(metadata);
assert(gc->uncompressed_root_set);
}
#else /* COMPRESS_REFERENCE */
inline void gc_rootset_add_entry(GC* gc, Partial_Reveal_Object** p_ref)
{
assert( p_ref < gc_heap_base_address() || p_ref >= gc_heap_ceiling_address());
Partial_Reveal_Object *p_obj = *p_ref;
Vector_Block* root_set = gc->root_set;
if(rootset_type == ROOTSET_IS_REF)
vector_block_add_entry(root_set, (POINTER_SIZE_INT)p_ref);
else if(rootset_type == ROOTSET_IS_OBJ)
vector_block_add_entry(root_set, (POINTER_SIZE_INT)p_obj);
if( !vector_block_is_full(root_set)) return;
pool_put_entry(gc_metadata.gc_rootset_pool, root_set);
gc->root_set = free_set_pool_get_entry(&gc_metadata);
assert(gc->root_set);
}
#endif
#endif /* #ifndef _GC_METADATA_H_ */