blob: acf124a912685fe39d34b2338e5f016ce736684b [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 Li-Gang Wang, 2006/11/29
*/
#include "finalizer_weakref_metadata.h"
#include "../thread/mutator.h"
#include "../thread/collector.h"
#include "../thread/conclctor.h"
#define FINREF_METADATA_SEG_SIZE_BIT_SHIFT 20
#define FINREF_METADATA_SEG_SIZE_BYTES (1 << FINREF_METADATA_SEG_SIZE_BIT_SHIFT)
#define FINREF_METADATA_BLOCK_SIZE_BIT_SHIFT 10
#define FINREF_METADATA_BLOCK_SIZE_BYTES (1 << FINREF_METADATA_BLOCK_SIZE_BIT_SHIFT)
static Finref_Metadata finref_metadata;
unsigned int get_gc_referent_offset(void)
{
return finref_metadata.gc_referent_offset;
}
void set_gc_referent_offset(unsigned int offset)
{
finref_metadata.gc_referent_offset = offset;
}
void gc_finref_metadata_initialize(GC *gc)
{
TRACE2("gc.process", "GC: gc finref metadata init ... \n");
unsigned int seg_size = FINREF_METADATA_SEG_SIZE_BYTES + FINREF_METADATA_BLOCK_SIZE_BYTES;
void *first_segment = STD_MALLOC(seg_size);
memset(first_segment, 0, seg_size);
finref_metadata.segments[0] = first_segment;
first_segment = (void*)round_up_to_size((POINTER_SIZE_INT)first_segment, FINREF_METADATA_BLOCK_SIZE_BYTES);
finref_metadata.num_alloc_segs = 1;
finref_metadata.alloc_lock = FREE_LOCK;
finref_metadata.free_pool = sync_pool_create();
finref_metadata.obj_with_fin_pool = sync_pool_create();
finref_metadata.finalizable_obj_pool = sync_pool_create();
finref_metadata.finalizable_obj_pool_copy = sync_pool_create();
finref_metadata.softref_pool = sync_pool_create();
finref_metadata.weakref_pool = sync_pool_create();
finref_metadata.phanref_pool = sync_pool_create();
finref_metadata.repset_pool = sync_pool_create();
finref_metadata.fallback_ref_pool = sync_pool_create();
finref_metadata.finalizable_obj_set= NULL;
finref_metadata.repset = NULL;
unsigned int num_blocks = FINREF_METADATA_SEG_SIZE_BYTES >> FINREF_METADATA_BLOCK_SIZE_BIT_SHIFT;
for(unsigned int i=0; i<num_blocks; i++){
Vector_Block *block = (Vector_Block *)((POINTER_SIZE_INT)first_segment + i*FINREF_METADATA_BLOCK_SIZE_BYTES);
vector_block_init(block, FINREF_METADATA_BLOCK_SIZE_BYTES);
assert(vector_block_is_empty((Vector_Block *)block));
pool_put_entry(finref_metadata.free_pool, (void *)block);
}
finref_metadata.pending_finalizers = FALSE;
finref_metadata.pending_weakrefs = FALSE;
finref_metadata.gc_referent_offset = 0;
gc->finref_metadata = &finref_metadata;
return;
}
void gc_finref_metadata_destruct(GC *gc)
{
TRACE2("gc.process", "GC: GC finref metadata destruct ...");
Finref_Metadata *metadata = gc->finref_metadata;
sync_pool_destruct(metadata->free_pool);
sync_pool_destruct(metadata->obj_with_fin_pool);
sync_pool_destruct(metadata->finalizable_obj_pool);
sync_pool_destruct(metadata->finalizable_obj_pool_copy);
sync_pool_destruct(metadata->softref_pool);
sync_pool_destruct(metadata->weakref_pool);
sync_pool_destruct(metadata->phanref_pool);
sync_pool_destruct(metadata->repset_pool);
metadata->finalizable_obj_set = NULL;
metadata->repset = NULL;
for(unsigned int i=0; i<metadata->num_alloc_segs; i++){
assert(metadata->segments[i]);
STD_FREE(metadata->segments[i]);
}
gc->finref_metadata = NULL;
}
void gc_finref_metadata_verify(GC *gc, Boolean is_before_gc)
{
Finref_Metadata *metadata = gc->finref_metadata;
assert(pool_is_empty(metadata->finalizable_obj_pool));
assert(pool_is_empty(metadata->softref_pool));
assert(pool_is_empty(metadata->weakref_pool));
assert(pool_is_empty(metadata->phanref_pool));
assert(pool_is_empty(metadata->repset_pool));
assert(metadata->finalizable_obj_set == NULL);
assert(metadata->repset == NULL);
return;
}
/* Extending the pool by a segment
* Called when there is no vector block in finref_metadata->free_pool
*/
Vector_Block *finref_metadata_extend(void)
{
Finref_Metadata *metadata = &finref_metadata;
lock(metadata->alloc_lock);
Vector_Block* block = pool_get_entry(metadata->free_pool);
if( block ){
unlock(metadata->alloc_lock);
return block;
}
unsigned int num_alloced = metadata->num_alloc_segs;
if(num_alloced == FINREF_METADATA_SEGMENT_NUM){
printf("Run out Finref metadata, please give it more segments!\n");
exit(0);
}
unsigned int seg_size = FINREF_METADATA_SEG_SIZE_BYTES + FINREF_METADATA_BLOCK_SIZE_BYTES;
void *new_segment = STD_MALLOC(seg_size);
memset(new_segment, 0, seg_size);
metadata->segments[num_alloced] = new_segment;
new_segment = (void*)round_up_to_size((POINTER_SIZE_INT)new_segment, FINREF_METADATA_BLOCK_SIZE_BYTES);
metadata->num_alloc_segs++;
unsigned int num_blocks = FINREF_METADATA_SEG_SIZE_BYTES >> FINREF_METADATA_BLOCK_SIZE_BIT_SHIFT;
for(unsigned int i=0; i<num_blocks; i++){
Vector_Block *block = (Vector_Block *)((POINTER_SIZE_INT)new_segment + i*FINREF_METADATA_BLOCK_SIZE_BYTES);
vector_block_init(block, FINREF_METADATA_BLOCK_SIZE_BYTES);
assert(vector_block_is_empty((Vector_Block *)block));
pool_put_entry(metadata->free_pool, (void *)block);
}
block = pool_get_entry(metadata->free_pool);
unlock(metadata->alloc_lock);
return block;
}
/* reset obj_with_fin vector block of each mutator */
static void gc_reset_obj_with_fin(GC *gc)
{
Mutator *mutator = gc->mutator_list;
while(mutator){
//assert(!mutator->obj_with_fin);
/* Workaround for the mutator num changing during GC bug */
if(mutator->obj_with_fin){
assert(vector_block_is_empty(mutator->obj_with_fin));
mutator = mutator->next;
continue;
}
mutator->obj_with_fin = finref_get_free_block(gc);
mutator = mutator->next;
}
}
/* put back last obj_with_fin block of each mutator */
void gc_set_obj_with_fin(GC *gc)
{
Pool *obj_with_fin_pool = gc->finref_metadata->obj_with_fin_pool;
Mutator *mutator = gc->mutator_list;
while(mutator){
pool_put_entry(obj_with_fin_pool, mutator->obj_with_fin);
mutator->obj_with_fin = finref_get_free_block(gc);
mutator = mutator->next;
}
}
/* reset weak references vetctor block of each collector */
void collector_reset_weakref_sets(Collector *collector)
{
GC *gc = collector->gc;
assert(collector->softref_set == NULL);
assert(collector->weakref_set == NULL);
assert(collector->phanref_set == NULL);
collector->softref_set = finref_get_free_block(gc);
collector->weakref_set = finref_get_free_block(gc);
collector->phanref_set= finref_get_free_block(gc);
}
#include "../common/gc_concurrent.h"
/* put back last weak references block of each collector */
void gc_set_weakref_sets(GC *gc)
{
Finref_Metadata *metadata = gc->finref_metadata;
unsigned int num_active_collectors = gc->num_active_collectors;
for(unsigned int i = 0; i < num_active_collectors; i++)
{
Collector *collector = gc->collectors[i];
if(!vector_block_is_empty(collector->softref_set))
pool_put_entry(metadata->softref_pool, collector->softref_set);
else
pool_put_entry(metadata->free_pool, collector->softref_set);
if(!vector_block_is_empty(collector->weakref_set))
pool_put_entry(metadata->weakref_pool, collector->weakref_set);
else
pool_put_entry(metadata->free_pool, collector->weakref_set);
if(!vector_block_is_empty(collector->phanref_set))
pool_put_entry(metadata->phanref_pool, collector->phanref_set);
else
pool_put_entry(metadata->free_pool, collector->phanref_set);
collector->softref_set = NULL;
collector->weakref_set= NULL;
collector->phanref_set= NULL;
}
return;
}
void gc_reset_finref_metadata(GC *gc)
{
Finref_Metadata *metadata = gc->finref_metadata;
Pool *obj_with_fin_pool = metadata->obj_with_fin_pool;
Pool *finalizable_obj_pool = metadata->finalizable_obj_pool;
assert(pool_is_empty(finalizable_obj_pool));
assert(pool_is_empty(metadata->softref_pool));
assert(pool_is_empty(metadata->weakref_pool));
assert(pool_is_empty(metadata->phanref_pool));
assert(metadata->finalizable_obj_set == NULL);
assert(metadata->repset == NULL);
if(!pool_is_empty(metadata->repset_pool))
finref_metadata_clear_pool(metadata->repset_pool);
if(!pool_is_empty(metadata->fallback_ref_pool))
finref_metadata_clear_pool(metadata->fallback_ref_pool);
/* Extract empty blocks in obj_with_fin_pool and put them into free_pool */
Vector_Block *block = pool_get_entry(obj_with_fin_pool);
while(block){
POINTER_SIZE_INT *iter = vector_block_iterator_init(block);
if(vector_block_iterator_end(block, iter)){
vector_block_clear(block);
pool_put_entry(metadata->free_pool, block);
} else {
pool_put_entry(finalizable_obj_pool, block);
}
block = pool_get_entry(obj_with_fin_pool);
}
assert(pool_is_empty(obj_with_fin_pool));
metadata->obj_with_fin_pool = finalizable_obj_pool;
metadata->finalizable_obj_pool = obj_with_fin_pool;
//gc_reset_obj_with_fin(gc);
}
static inline Vector_Block *finref_metadata_add_entry(GC *gc, Vector_Block *vector_block_in_use, Pool *pool, POINTER_SIZE_INT value)
{
assert(vector_block_in_use);
assert(!vector_block_is_full(vector_block_in_use));
assert(value);
vector_block_add_entry(vector_block_in_use, value);
if(!vector_block_is_full(vector_block_in_use))
return vector_block_in_use;
pool_put_entry(pool, vector_block_in_use);
return finref_get_free_block(gc);
}
void mutator_add_finalizer(Mutator *mutator, Partial_Reveal_Object *p_obj)
{
GC *gc = mutator->gc;
Finref_Metadata *metadata = gc->finref_metadata;
mutator->obj_with_fin = finref_metadata_add_entry(gc, mutator->obj_with_fin, metadata->obj_with_fin_pool, (POINTER_SIZE_INT)obj_ptr_to_ref(p_obj));
}
/* This function is only used by resurrection fallback */
Vector_Block *gc_add_finalizer(GC *gc, Vector_Block *vector_block_in_use, Partial_Reveal_Object *p_obj)
{
Finref_Metadata *metadata = gc->finref_metadata;
return finref_metadata_add_entry(gc, vector_block_in_use, metadata->obj_with_fin_pool, (POINTER_SIZE_INT)obj_ptr_to_ref(p_obj));
}
void gc_add_finalizable_obj(GC *gc, Partial_Reveal_Object *p_obj)
{
Finref_Metadata *metadata = gc->finref_metadata;
metadata->finalizable_obj_set = finref_metadata_add_entry(gc, metadata->finalizable_obj_set, metadata->finalizable_obj_pool, (POINTER_SIZE_INT)obj_ptr_to_ref(p_obj));
}
void collector_add_softref(Collector *collector, Partial_Reveal_Object *ref)
{
GC *gc = collector->gc;
Finref_Metadata *metadata = gc->finref_metadata;
collector->softref_set = finref_metadata_add_entry(gc, collector->softref_set, metadata->softref_pool, (POINTER_SIZE_INT)obj_ptr_to_ref(ref));
}
void collector_add_weakref(Collector *collector, Partial_Reveal_Object *ref)
{
GC *gc = collector->gc;
Finref_Metadata *metadata = gc->finref_metadata;
collector->weakref_set = finref_metadata_add_entry(gc, collector->weakref_set, metadata->weakref_pool, (POINTER_SIZE_INT)obj_ptr_to_ref(ref));
}
void collector_add_phanref(Collector *collector, Partial_Reveal_Object *ref)
{
GC *gc = collector->gc;
Finref_Metadata *metadata = gc->finref_metadata;
collector->phanref_set = finref_metadata_add_entry(gc, collector->phanref_set, metadata->phanref_pool, (POINTER_SIZE_INT)obj_ptr_to_ref(ref));
}
void finref_repset_add_entry(GC *gc, REF* p_ref)
{
assert(*p_ref);
assert(read_slot(p_ref));
Finref_Metadata *metadata = gc->finref_metadata;
metadata->repset = finref_metadata_add_entry(gc, metadata->repset, metadata->repset_pool, (POINTER_SIZE_INT)p_ref);
}
/* This function is only used by resurrection fallback */
Vector_Block *finref_add_fallback_ref(GC *gc, Vector_Block *vector_block_in_use, Partial_Reveal_Object *p_obj)
{
assert(p_obj);
Finref_Metadata *metadata = gc->finref_metadata;
return finref_metadata_add_entry(gc, vector_block_in_use, metadata->fallback_ref_pool, (POINTER_SIZE_INT)obj_ptr_to_ref(p_obj));
}
static Boolean pool_has_no_ref(Pool *pool)
{
if(pool_is_empty(pool))
return TRUE;
pool_iterator_init(pool);
Vector_Block *block = pool_iterator_next(pool);
while(block){
POINTER_SIZE_INT *iter = vector_block_iterator_init(block);
while(!vector_block_iterator_end(block, iter)){
if(*iter)
return FALSE;
iter = vector_block_iterator_advance(block, iter);
}
block = pool_iterator_next(pool);
}
return TRUE;
}
Boolean obj_with_fin_pool_is_empty(GC *gc)
{
return pool_has_no_ref(gc->finref_metadata->obj_with_fin_pool);
}
Boolean finalizable_obj_pool_is_empty(GC *gc)
{
return pool_has_no_ref(gc->finref_metadata->finalizable_obj_pool);
}
Boolean softref_pool_is_empty(GC *gc)
{
return pool_has_no_ref(gc->finref_metadata->softref_pool);
}
Boolean weakref_pool_is_empty(GC *gc)
{
return pool_has_no_ref(gc->finref_metadata->weakref_pool);
}
Boolean phanref_pool_is_empty(GC *gc)
{
return pool_has_no_ref(gc->finref_metadata->phanref_pool);
}
Boolean finref_repset_pool_is_empty(GC *gc)
{
return pool_has_no_ref(gc->finref_metadata->repset_pool);
}
void finref_metadata_clear_pool(Pool *pool)
{
while(Vector_Block* block = pool_get_entry(pool)){
vector_block_clear(block);
pool_put_entry(finref_metadata.free_pool, block);
}
}
void gc_clear_weakref_pools(GC *gc)
{
finref_metadata_clear_pool(gc->finref_metadata->softref_pool);
finref_metadata_clear_pool(gc->finref_metadata->weakref_pool);
finref_metadata_clear_pool(gc->finref_metadata->phanref_pool);
}
void gc_clear_finref_repset_pool(GC* gc)
{
finref_metadata_clear_pool(gc->finref_metadata->repset_pool);
}
Boolean finref_copy_pool(Pool *src_pool, Pool *dest_pool, GC *gc)
{
Vector_Block *dest_block = finref_get_free_block(gc);
pool_iterator_init(src_pool);
while(Vector_Block *src_block = pool_iterator_next(src_pool)){
POINTER_SIZE_INT *iter = vector_block_iterator_init(src_block);
while(!vector_block_iterator_end(src_block, iter)){
assert(*iter);
finref_metadata_add_entry(gc, dest_block, dest_pool, *iter);
iter = vector_block_iterator_advance(src_block, iter);
}
}
return TRUE;
}