blob: 3828374fefb7e68ef76c294ffcb12855b851e74c [file]
/*
* 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/05
*/
#include "gc_common.h"
#include "open/vm_field_access.h"
#include "open/vm_class_manipulation.h"
#include "../finalizer_weakref/finalizer_weakref.h"
/* Setter functions for the gc class property field. */
void gc_set_prop_alignment_mask (GC_VTable_Info *gcvt, unsigned int the_mask)
{
gcvt->gc_class_properties |= the_mask;
}
void gc_set_prop_non_ref_array (GC_VTable_Info *gcvt)
{
gcvt->gc_class_properties |= CL_PROP_NON_REF_ARRAY_MASK;
}
void gc_set_prop_array (GC_VTable_Info *gcvt)
{
gcvt->gc_class_properties |= CL_PROP_ARRAY_MASK;
}
void gc_set_prop_pinned (GC_VTable_Info *gcvt)
{
gcvt->gc_class_properties |= CL_PROP_PINNED_MASK;
}
void gc_set_prop_finalizable (GC_VTable_Info *gcvt)
{
gcvt->gc_class_properties |= CL_PROP_FINALIZABLE_MASK;
}
void gc_set_prop_reference(GC_VTable_Info *gcvt, WeakReferenceType type)
{
gcvt->gc_class_properties |= (unsigned int)type << CL_PROP_REFERENCE_TYPE_SHIFT;
}
/* A comparison function for qsort() called below to order offset slots. */
static int intcompare(const void *vi, const void *vj)
{
const int *i = (const int *) vi;
const int *j = (const int *) vj;
if (*i > *j)
return 1;
if (*i < *j)
return -1;
return 0;
}
static unsigned int class_num_ref_fields(Class_Handle ch)
{
WeakReferenceType is_reference = class_is_reference(ch);
unsigned num_ref_fields = 0;
unsigned num_fields = class_num_instance_fields_recursive(ch);
unsigned idx;
for(idx = 0; idx < num_fields; idx++) {
Field_Handle fh = class_get_instance_field_recursive(ch, idx);
if(field_is_reference(fh)) {
num_ref_fields++;
}
}
#ifndef BUILD_IN_REFERENT
if (is_reference != NOT_REFERENCE) {
unsigned int offset = class_get_referent_offset(ch);
unsigned int gc_referent_offset = get_gc_referent_offset();
if (gc_referent_offset == 0) {
set_gc_referent_offset(offset);
} else {
assert(gc_referent_offset == offset);
}
num_ref_fields--;
}
#endif
return num_ref_fields;
}
static void build_ref_offset_array(Class_Handle ch, GC_VTable_Info *gcvt)
{
unsigned num_fields = class_num_instance_fields_recursive(ch);
WeakReferenceType is_reference = class_is_reference(ch);
unsigned int gc_referent_offset = get_gc_referent_offset();
int *new_ref_array = gcvt->gc_ref_offset_array;
int *result = new_ref_array;
for(unsigned int idx = 0; idx < num_fields; idx++) {
Field_Handle fh = class_get_instance_field_recursive(ch, idx);
if(field_is_reference(fh)) {
int offset = field_get_offset(fh);
#ifndef BUILD_IN_REFERENT
if(is_reference && (offset == gc_referent_offset)) continue;
#endif
*new_ref_array = field_get_offset(fh);
new_ref_array++;
}
}
/* ref array is NULL-terminated */
*new_ref_array = 0;
unsigned int num_ref_fields = gcvt->gc_number_of_ref_fields;
/* offsets were built with idx, may not be in order. Let's sort it anyway.
FIXME: verify_live_heap depends on ordered offset array. */
qsort(gcvt->gc_ref_offset_array, num_ref_fields, sizeof(int), intcompare);
return;
}
void gc_class_prepared (Class_Handle ch, VTable_Handle vth)
{
GC_VTable_Info *gcvt;
assert(ch);
assert(vth);
Partial_Reveal_VTable *vt = (Partial_Reveal_VTable *)vth;
unsigned int num_ref_fields = class_num_ref_fields(ch);
unsigned int gcvt_size = sizeof(GC_VTable_Info);
if(num_ref_fields){
gcvt_size += num_ref_fields * sizeof(unsigned int);
}
gcvt_size = (gcvt_size + GCVT_ALIGN_MASK) & ~GCVT_ALIGN_MASK;
gcvt = (GC_VTable_Info*) class_alloc_via_classloader(ch, gcvt_size);
assert(gcvt);
assert(!((POINTER_SIZE_INT)gcvt % GCVT_ALIGNMENT));
memset((void *)gcvt, 0, gcvt_size);
gcvt->gc_clss = ch;
gcvt->gc_class_properties = 0;
gc_set_prop_alignment_mask(gcvt, class_get_alignment(ch));
if(num_ref_fields){
gcvt->gc_number_of_ref_fields = num_ref_fields;
/* Build the offset array */
build_ref_offset_array(ch, gcvt);
}
if(class_is_array(ch)) {
Class_Handle array_element_class = class_get_array_element_class(ch);
gc_set_prop_array(gcvt);
gcvt->array_elem_size = class_get_array_element_size(ch);
unsigned int the_offset = vector_first_element_offset_unboxed(array_element_class);
gcvt->array_first_elem_offset = the_offset;
if (class_is_non_ref_array (ch)) {
gc_set_prop_non_ref_array(gcvt);
}else{
gcvt->gc_number_of_ref_fields = 1;
}
}
if (class_is_finalizable(ch)) {
gc_set_prop_finalizable(gcvt);
}
WeakReferenceType type = class_is_reference(ch);
gc_set_prop_reference(gcvt, type);
unsigned int size = class_get_object_size(ch);
gcvt->gc_allocated_size = size;
gcvt->gc_class_name = class_get_name(ch);
assert (gcvt->gc_class_name);
/* these should be set last to use the gcvt pointer */
if(gcvt->gc_number_of_ref_fields)
gcvt = (GC_VTable_Info*)((POINTER_SIZE_INT)gcvt | GC_CLASS_FLAG_REFS);
if(class_is_array(ch))
gcvt = (GC_VTable_Info*)((POINTER_SIZE_INT)gcvt | GC_CLASS_FLAG_ARRAY);
if(class_is_finalizable(ch))
gcvt = (GC_VTable_Info*)((POINTER_SIZE_INT)gcvt | GC_CLASS_FLAG_FINALIZER);
vtable_set_gcvt(vt, gcvt);
return;
} /* gc_class_prepared */