In gcc/java:
* class.c (make_class_data): Push initial value for "arrayclass". * decl.c (init_decl_processing): Add new class field "arrayclass". In libjava: * java/lang/Class.h (_Jv_InitClass): Use __builtin_expect. (_Jv_NewArrayClass): Renamed from _Jv_FindArrayClass. (_Jv_GetArrayClass): New inline function. (arrayclass): New field. * prims.cc (_Jv_NewObjectArray): Use _Jv_GetArrayClass. Don't use _Jv_GetArrayElementFromElementType. (_Jv_NewPrimArray): Ditto. (_Jv_PrimClass constructor): Initialize "depth", "ancestors", and "idt" for completeness. Initialze "arrayclass" using _Jv_NewArrayClass. Set Modifier::ABSTRACT. * java/lang/natClassLoader.cc (_Jv_NewClass): Initialize "arrayclass". (_Jv_NewArrayClass): Renamed from _Jv_FindArrayClass. Now void. Now synchronized. Array classes are now referenced from elementClass->arrayclass. Don't use _Jv_FindClassInCache. Set array classes' accessibility flags correctly. Optimize so that all array classes share the same IDT. * java/lang/reflect/natArray.cc (newInstance): Use _Jv_GetArrayClass. * java/lang/reflect/natMethod.cc (_Jv_GetTypesFromSignature): Ditto. * java/lang/natClass.cc (_getFields): Increment offset. Prevent fields in superclasses from overwriting classes own fields. (_Jv_IsAssignableFrom): Check for NULL source idt instead of calling Modifier::isAbstract(). (null_idt): New static field. (_Jv_PrepareConstantTimeTables): Optimize case where class implements no interfaces. (_Jv_IndexOf): Made inline. * boehm.cc (_Jv_MarkObj): Mark "arrayclass" field. From-SVN: r38808
This commit is contained in:
parent
5bab9296f5
commit
5bb11b2e20
11 changed files with 174 additions and 94 deletions
|
@ -210,7 +210,7 @@ private:
|
|||
inline friend void
|
||||
_Jv_InitClass (jclass klass)
|
||||
{
|
||||
if (klass->state == JV_STATE_DONE)
|
||||
if (__builtin_expect (klass->state == JV_STATE_DONE, true))
|
||||
return;
|
||||
klass->initializeClass ();
|
||||
}
|
||||
|
@ -254,9 +254,9 @@ private:
|
|||
java::lang::ClassLoader *loader);
|
||||
friend jclass _Jv_FindClassInCache (_Jv_Utf8Const *name,
|
||||
java::lang::ClassLoader *loader);
|
||||
friend jclass _Jv_FindArrayClass (jclass element,
|
||||
java::lang::ClassLoader *loader,
|
||||
_Jv_VTable *array_vtable = 0);
|
||||
friend void _Jv_NewArrayClass (jclass element,
|
||||
java::lang::ClassLoader *loader,
|
||||
_Jv_VTable *array_vtable = 0);
|
||||
friend jclass _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass,
|
||||
java::lang::ClassLoader *loader);
|
||||
|
||||
|
@ -268,6 +268,16 @@ private:
|
|||
friend jshort _Jv_AppendPartialITable (jclass, jclass, void **, jshort);
|
||||
friend jshort _Jv_FindIIndex (jclass *, jshort *, jshort);
|
||||
|
||||
// Return array class corresponding to element type KLASS, creating it if
|
||||
// neccessary.
|
||||
inline friend jclass
|
||||
_Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader)
|
||||
{
|
||||
if (__builtin_expect (!klass->arrayclass, false))
|
||||
_Jv_NewArrayClass (klass, loader);
|
||||
return klass->arrayclass;
|
||||
}
|
||||
|
||||
#ifdef INTERPRETER
|
||||
friend jboolean _Jv_IsInterpretedClass (jclass);
|
||||
friend void _Jv_InitField (jobject, jclass, _Jv_Field*);
|
||||
|
@ -302,8 +312,7 @@ private:
|
|||
// Class constants.
|
||||
_Jv_Constants constants;
|
||||
// Methods. If this is an array class, then this field holds a
|
||||
// pointer to the element type. If this is a primitive class, this
|
||||
// is used to cache a pointer to the appropriate array type.
|
||||
// pointer to the element type.
|
||||
_Jv_Method *methods;
|
||||
// Number of methods. If this class is primitive, this holds the
|
||||
// character used to represent this type in a signature.
|
||||
|
@ -337,6 +346,8 @@ private:
|
|||
jclass *ancestors;
|
||||
// Interface Dispatch Table.
|
||||
_Jv_IDispatchTable *idt;
|
||||
// Pointer to the class that represents an array of this class.
|
||||
jclass arrayclass;
|
||||
};
|
||||
|
||||
#endif /* __JAVA_LANG_CLASS_H__ */
|
||||
|
|
|
@ -421,7 +421,7 @@ java::lang::Class::_getFields (JArray<java::lang::reflect::Field *> *result,
|
|||
rfield->offset = (char *) field - (char *) fields;
|
||||
rfield->declaringClass = this;
|
||||
rfield->name = _Jv_NewStringUtf8Const (field->name);
|
||||
(elements (result))[offset + i] = rfield;
|
||||
(elements (result))[offset++] = rfield;
|
||||
}
|
||||
}
|
||||
jclass superclass = getSuperclass();
|
||||
|
@ -929,8 +929,7 @@ _Jv_IsAssignableFrom (jclass target, jclass source)
|
|||
// Abstract classes have no IDT, and IDTs provide no way to check
|
||||
// two interfaces for assignability.
|
||||
if (__builtin_expect
|
||||
(java::lang::reflect::Modifier::isAbstract (source->accflags)
|
||||
|| source->isInterface(), false))
|
||||
(source->idt == NULL || source->isInterface(), false))
|
||||
return _Jv_InterfaceAssignableFrom (target, source);
|
||||
|
||||
_Jv_IDispatchTable *cl_idt = source->idt;
|
||||
|
@ -1007,6 +1006,8 @@ _Jv_CheckArrayStore (jobject arr, jobject obj)
|
|||
#define INITIAL_IOFFSETS_LEN 4
|
||||
#define INITIAL_IFACES_LEN 4
|
||||
|
||||
static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} };
|
||||
|
||||
// Generate tables for constant-time assignment testing and interface
|
||||
// method lookup. This implements the technique described by Per Bothner
|
||||
// <per@bothner.com> on the java-discuss mailing list on 1999-09-02:
|
||||
|
@ -1028,8 +1029,10 @@ _Jv_PrepareConstantTimeTables (jclass klass)
|
|||
// interfaces or primitive types.
|
||||
|
||||
jclass klass0 = klass;
|
||||
jboolean has_interfaces = 0;
|
||||
while (klass0 != &ObjectClass)
|
||||
{
|
||||
has_interfaces += klass0->interface_count;
|
||||
klass0 = klass0->superclass;
|
||||
klass->depth++;
|
||||
}
|
||||
|
@ -1051,6 +1054,14 @@ _Jv_PrepareConstantTimeTables (jclass klass)
|
|||
|
||||
if (java::lang::reflect::Modifier::isAbstract (klass->accflags))
|
||||
return;
|
||||
|
||||
// Optimization: If class implements no interfaces, use a common
|
||||
// predefined interface table.
|
||||
if (!has_interfaces)
|
||||
{
|
||||
klass->idt = &null_idt;
|
||||
return;
|
||||
}
|
||||
|
||||
klass->idt =
|
||||
(_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
|
||||
|
@ -1095,7 +1106,7 @@ _Jv_PrepareConstantTimeTables (jclass klass)
|
|||
}
|
||||
|
||||
// Return index of item in list, or -1 if item is not present.
|
||||
jshort
|
||||
inline jshort
|
||||
_Jv_IndexOf (void *item, void **list, jshort list_len)
|
||||
{
|
||||
for (int i=0; i < list_len; i++)
|
||||
|
|
|
@ -530,26 +530,35 @@ _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass,
|
|||
ret->depth = 0;
|
||||
ret->ancestors = NULL;
|
||||
ret->idt = NULL;
|
||||
ret->arrayclass = NULL;
|
||||
|
||||
_Jv_RegisterClass (ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
jclass
|
||||
_Jv_FindArrayClass (jclass element, java::lang::ClassLoader *loader,
|
||||
_Jv_VTable *array_vtable)
|
||||
static _Jv_IDispatchTable *array_idt = NULL;
|
||||
static jshort array_depth = 0;
|
||||
static jclass *array_ancestors = NULL;
|
||||
|
||||
// Create a class representing an array of ELEMENT and store a pointer to it
|
||||
// in element->arrayclass. LOADER is the ClassLoader which _initiated_ the
|
||||
// instantiation of this array. ARRAY_VTABLE is the vtable to use for the new
|
||||
// array class. This parameter is optional.
|
||||
void
|
||||
_Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader,
|
||||
_Jv_VTable *array_vtable)
|
||||
{
|
||||
JvSynchronize sync (element);
|
||||
|
||||
_Jv_Utf8Const *array_name;
|
||||
int len;
|
||||
|
||||
if (element->arrayclass)
|
||||
return;
|
||||
|
||||
if (element->isPrimitive())
|
||||
{
|
||||
// For primitive types the array is cached in the class.
|
||||
jclass ret = (jclass) element->methods;
|
||||
if (ret)
|
||||
return ret;
|
||||
len = 3;
|
||||
}
|
||||
len = 3;
|
||||
else
|
||||
len = element->name->length + 5;
|
||||
|
||||
|
@ -557,7 +566,7 @@ _Jv_FindArrayClass (jclass element, java::lang::ClassLoader *loader,
|
|||
char signature[len];
|
||||
int index = 0;
|
||||
signature[index++] = '[';
|
||||
// Compute name of array class to see if we've already cached it.
|
||||
// Compute name of array class.
|
||||
if (element->isPrimitive())
|
||||
{
|
||||
signature[index++] = (char) element->method_count;
|
||||
|
@ -576,65 +585,76 @@ _Jv_FindArrayClass (jclass element, java::lang::ClassLoader *loader,
|
|||
array_name = _Jv_makeUtf8Const (signature, index);
|
||||
}
|
||||
|
||||
jclass array_class = _Jv_FindClassInCache (array_name, element->loader);
|
||||
// Create new array class.
|
||||
jclass array_class = _Jv_NewClass (array_name, &ObjectClass,
|
||||
element->loader);
|
||||
|
||||
if (! array_class)
|
||||
// Note that `vtable_method_count' doesn't include the initial
|
||||
// gc_descr slot.
|
||||
JvAssert (ObjectClass.vtable_method_count == NUM_OBJECT_METHODS);
|
||||
int dm_count = ObjectClass.vtable_method_count;
|
||||
|
||||
// Create a new vtable by copying Object's vtable (except the
|
||||
// class pointer, of course). Note that we allocate this as
|
||||
// unscanned memory -- the vtables are handled specially by the
|
||||
// GC.
|
||||
int size = (sizeof (_Jv_VTable) + ((dm_count - 1) * sizeof (void *)));
|
||||
_Jv_VTable *vtable;
|
||||
if (array_vtable)
|
||||
vtable = array_vtable;
|
||||
else
|
||||
vtable = (_Jv_VTable *) _Jv_AllocBytes (size);
|
||||
vtable->clas = array_class;
|
||||
memcpy (vtable->method, ObjectClass.vtable->method,
|
||||
dm_count * sizeof (void *));
|
||||
vtable->gc_descr = ObjectClass.vtable->gc_descr;
|
||||
array_class->vtable = vtable;
|
||||
array_class->vtable_method_count = ObjectClass.vtable_method_count;
|
||||
|
||||
// Stash the pointer to the element type.
|
||||
array_class->methods = (_Jv_Method *) element;
|
||||
|
||||
// Register our interfaces.
|
||||
static jclass interfaces[] = { &CloneableClass, &SerializableClass };
|
||||
array_class->interfaces = interfaces;
|
||||
array_class->interface_count = sizeof interfaces / sizeof interfaces[0];
|
||||
|
||||
// Since all array classes have the same interface dispatch table, we can
|
||||
// cache one and reuse it. It is not neccessary to synchronize this.
|
||||
if (!array_idt)
|
||||
{
|
||||
// Create new array class.
|
||||
array_class = _Jv_NewClass (array_name, &ObjectClass, element->loader);
|
||||
|
||||
// Note that `vtable_method_count' doesn't include the initial
|
||||
// gc_descr slot.
|
||||
JvAssert (ObjectClass.vtable_method_count == NUM_OBJECT_METHODS);
|
||||
int dm_count = ObjectClass.vtable_method_count;
|
||||
|
||||
// Create a new vtable by copying Object's vtable (except the
|
||||
// class pointer, of course). Note that we allocate this as
|
||||
// unscanned memory -- the vtables are handled specially by the
|
||||
// GC.
|
||||
int size = (sizeof (_Jv_VTable) + ((dm_count - 1) * sizeof (void *)));
|
||||
_Jv_VTable *vtable;
|
||||
if (array_vtable)
|
||||
vtable = array_vtable;
|
||||
else
|
||||
vtable = (_Jv_VTable *) _Jv_AllocBytes (size);
|
||||
vtable->clas = array_class;
|
||||
memcpy (vtable->method, ObjectClass.vtable->method,
|
||||
dm_count * sizeof (void *));
|
||||
vtable->gc_descr = ObjectClass.vtable->gc_descr;
|
||||
array_class->vtable = vtable;
|
||||
array_class->vtable_method_count = ObjectClass.vtable_method_count;
|
||||
|
||||
// Stash the pointer to the element type.
|
||||
array_class->methods = (_Jv_Method *) element;
|
||||
|
||||
// Register our interfaces.
|
||||
static jclass interfaces[] = { &CloneableClass, &SerializableClass };
|
||||
array_class->interfaces = interfaces;
|
||||
array_class->interface_count = sizeof interfaces / sizeof interfaces[0];
|
||||
|
||||
// FIXME: Shouldn't this be synchronized? _Jv_PrepareConstantTimeTables
|
||||
// needs to be called with the mutex for array_class held.
|
||||
// Generate the interface dispatch table.
|
||||
_Jv_PrepareConstantTimeTables (array_class);
|
||||
|
||||
// as per vmspec 5.3.3.2
|
||||
array_class->accflags = element->accflags;
|
||||
|
||||
// FIXME: initialize other Class instance variables,
|
||||
// e.g. `fields'.
|
||||
|
||||
// say this class is initialized and ready to go!
|
||||
array_class->state = JV_STATE_DONE;
|
||||
|
||||
// vmspec, section 5.3.3 describes this
|
||||
if (element->loader != loader)
|
||||
_Jv_RegisterInitiatingLoader (array_class, loader);
|
||||
array_idt = array_class->idt;
|
||||
array_depth = array_class->depth;
|
||||
array_ancestors = array_class->ancestors;
|
||||
}
|
||||
else
|
||||
{
|
||||
array_class->idt = array_idt;
|
||||
array_class->depth = array_depth;
|
||||
array_class->ancestors = array_ancestors;
|
||||
}
|
||||
|
||||
// For primitive types, point back at this array.
|
||||
if (element->isPrimitive())
|
||||
element->methods = (_Jv_Method *) array_class;
|
||||
using namespace java::lang::reflect;
|
||||
{
|
||||
// Array classes are "abstract final"...
|
||||
_Jv_ushort accflags = Modifier::FINAL | Modifier::ABSTRACT;
|
||||
// ... and inherit accessibility from element type, per vmspec 5.3.3.2
|
||||
accflags |= (element->accflags & Modifier::PUBLIC);
|
||||
accflags |= (element->accflags & Modifier::PROTECTED);
|
||||
accflags |= (element->accflags & Modifier::PRIVATE);
|
||||
array_class->accflags = accflags;
|
||||
}
|
||||
|
||||
return array_class;
|
||||
// An array class has no visible instance fields. "length" is invisible to
|
||||
// reflection.
|
||||
|
||||
// say this class is initialized and ready to go!
|
||||
array_class->state = JV_STATE_DONE;
|
||||
|
||||
// vmspec, section 5.3.3 describes this
|
||||
if (element->loader != loader)
|
||||
_Jv_RegisterInitiatingLoader (array_class, loader);
|
||||
|
||||
element->arrayclass = array_class;
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ java::lang::reflect::Array::newInstance (jclass componentType, jintArray dimensi
|
|||
jclass arrayType = componentType;
|
||||
for (int i = 0; i < ndims; i++) // FIXME 2nd arg should
|
||||
// be "current" loader
|
||||
arrayType = _Jv_FindArrayClass (arrayType, 0);
|
||||
arrayType = _Jv_GetArrayClass (arrayType, 0);
|
||||
|
||||
return _Jv_NewMultiArray (arrayType, ndims, dims);
|
||||
}
|
||||
|
|
|
@ -286,7 +286,7 @@ _Jv_GetTypesFromSignature (jmethodID method,
|
|||
|
||||
// FIXME: 2'nd argument should be "current loader"
|
||||
while (--num_arrays >= 0)
|
||||
type = _Jv_FindArrayClass (type, 0);
|
||||
type = _Jv_GetArrayClass (type, 0);
|
||||
// ARGPTR can be NULL if we are processing the return value of a
|
||||
// call from Constructor.
|
||||
if (argPtr)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue