From 5bb11b2e20b893361704d444fcf3a02de7f0bc89 Mon Sep 17 00:00:00 2001 From: Bryce McKinlay Date: Mon, 8 Jan 2001 23:28:56 +0000 Subject: [PATCH] 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 --- gcc/java/ChangeLog | 5 + gcc/java/class.c | 1 + gcc/java/decl.c | 1 + libjava/ChangeLog | 30 +++++ libjava/boehm.cc | 2 + libjava/java/lang/Class.h | 23 +++- libjava/java/lang/natClass.cc | 19 +++- libjava/java/lang/natClassLoader.cc | 150 ++++++++++++++----------- libjava/java/lang/reflect/natArray.cc | 2 +- libjava/java/lang/reflect/natMethod.cc | 2 +- libjava/prims.cc | 31 +++-- 11 files changed, 173 insertions(+), 93 deletions(-) diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index e3e7e46aa3e..ebf96fac18f 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,8 @@ +2001-01-05 Bryce McKinlay + + * class.c (make_class_data): Push initial value for "arrayclass". + * decl.c (init_decl_processing): Add new class field "arrayclass". + 2001-01-05 Bryce McKinlay From patha@softlab.ericsson.se: diff --git a/gcc/java/class.c b/gcc/java/class.c index 92dd0b971cd..ae715f14efc 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -1441,6 +1441,7 @@ make_class_data (type) PUSH_FIELD_VALUE (cons, "depth", integer_zero_node); PUSH_FIELD_VALUE (cons, "ancestors", null_pointer_node); PUSH_FIELD_VALUE (cons, "idt", null_pointer_node); + PUSH_FIELD_VALUE (cons, "arrayclass", null_pointer_node); FINISH_RECORD_CONSTRUCTOR (cons); diff --git a/gcc/java/decl.c b/gcc/java/decl.c index df6b236e45e..8d7887809e9 100644 --- a/gcc/java/decl.c +++ b/gcc/java/decl.c @@ -672,6 +672,7 @@ init_decl_processing () PUSH_FIELD (class_type_node, field, "depth", short_type_node); PUSH_FIELD (class_type_node, field, "ancestors", ptr_type_node); PUSH_FIELD (class_type_node, field, "idt", ptr_type_node); + PUSH_FIELD (class_type_node, field, "arrayclass", ptr_type_node); for (t = TYPE_FIELDS (class_type_node); t != NULL_TREE; t = TREE_CHAIN (t)) FIELD_PRIVATE (t) = 1; push_super_field (class_type_node, object_type_node); diff --git a/libjava/ChangeLog b/libjava/ChangeLog index e76f2f44ba8..42421be56da 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,33 @@ +2001-01-08 Bryce McKinlay + + * 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. + 2001-01-08 Tom Tromey Fix for PR java/1586: diff --git a/libjava/boehm.cc b/libjava/boehm.cc index 877d97c9d9c..49b4eab27fd 100644 --- a/libjava/boehm.cc +++ b/libjava/boehm.cc @@ -225,6 +225,8 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * /* env */) } p = (ptr_t) c->loader; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cBlabel); + p = (ptr_t) c->arrayclass; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cDlabel); #ifdef INTERPRETER if (_Jv_IsInterpretedClass (c)) diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index edaebb3245a..12e3ed5838f 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -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__ */ diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 4d45d07e39c..3a02b46a8af 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -421,7 +421,7 @@ java::lang::Class::_getFields (JArray *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 // 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++) diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc index f1704edd9aa..979de3fc2d6 100644 --- a/libjava/java/lang/natClassLoader.cc +++ b/libjava/java/lang/natClassLoader.cc @@ -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); - - if (! array_class) + // Create new array class. + jclass 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]; + + // 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); + 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; + } - // as per vmspec 5.3.3.2 - array_class->accflags = element->accflags; - - // FIXME: initialize other Class instance variables, - // e.g. `fields'. + 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; + } - // say this class is initialized and ready to go! - array_class->state = JV_STATE_DONE; + // An array class has no visible instance fields. "length" is invisible to + // reflection. - // vmspec, section 5.3.3 describes this - if (element->loader != loader) - _Jv_RegisterInitiatingLoader (array_class, loader); - } + // say this class is initialized and ready to go! + array_class->state = JV_STATE_DONE; - // For primitive types, point back at this array. - if (element->isPrimitive()) - element->methods = (_Jv_Method *) array_class; + // vmspec, section 5.3.3 describes this + if (element->loader != loader) + _Jv_RegisterInitiatingLoader (array_class, loader); - return array_class; + element->arrayclass = array_class; } diff --git a/libjava/java/lang/reflect/natArray.cc b/libjava/java/lang/reflect/natArray.cc index b5a2124fb6d..1680456d0b3 100644 --- a/libjava/java/lang/reflect/natArray.cc +++ b/libjava/java/lang/reflect/natArray.cc @@ -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); } diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index 26886e9bd85..4e9d3ceea4a 100644 --- a/libjava/java/lang/reflect/natMethod.cc +++ b/libjava/java/lang/reflect/natMethod.cc @@ -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) diff --git a/libjava/prims.cc b/libjava/prims.cc index 06585749c5f..c4c7316dfce 100644 --- a/libjava/prims.cc +++ b/libjava/prims.cc @@ -394,19 +394,13 @@ _Jv_NewObjectArray (jsize count, jclass elementClass, jobject init) JvAssert (! elementClass->isPrimitive ()); + // Ensure that elements pointer is properly aligned. jobjectArray obj = NULL; - size_t size = (size_t) _Jv_GetArrayElementFromElementType (obj, - elementClass); - - // Check for overflow. - if (__builtin_expect ((size_t) count > - (SIZE_T_MAX - size) / sizeof (jobject), false)) - JvThrow (no_memory); - + size_t size = (size_t) elements (obj); size += count * sizeof (jobject); - // FIXME: second argument should be "current loader" // - jclass klass = _Jv_FindArrayClass (elementClass, 0); + // FIXME: second argument should be "current loader" + jclass klass = _Jv_GetArrayClass (elementClass, 0); obj = (jobjectArray) _Jv_AllocArray (size, klass); if (__builtin_expect (! obj, false)) @@ -414,11 +408,11 @@ _Jv_NewObjectArray (jsize count, jclass elementClass, jobject init) // Cast away const. jsize *lp = const_cast (&obj->length); *lp = count; - jobject *ptr = elements(obj); // We know the allocator returns zeroed memory. So don't bother // zeroing it again. if (init) { + jobject *ptr = elements(obj); while (--count >= 0) *ptr++ = init; } @@ -443,7 +437,7 @@ _Jv_NewPrimArray (jclass eltype, jint count) (SIZE_T_MAX - size) / elsize, false)) JvThrow (no_memory); - jclass klass = _Jv_FindArrayClass (eltype, 0); + jclass klass = _Jv_GetArrayClass (eltype, 0); __JArray *arr = (__JArray*) _Jv_AllocObj (size + elsize * count, klass); if (__builtin_expect (! arr, false)) @@ -529,7 +523,7 @@ public: // the same order they are declared in Class.h. next = NULL; name = _Jv_makeUtf8Const ((char *) cname, -1); - accflags = Modifier::PUBLIC | Modifier::FINAL; + accflags = Modifier::PUBLIC | Modifier::FINAL | Modifier::ABSTRACT; superclass = NULL; constants.size = 0; constants.tags = NULL; @@ -547,10 +541,15 @@ public: interface_count = 0; state = JV_STATE_DONE; thread = NULL; + depth = -1; + ancestors = NULL; + idt = NULL; // Note that we have to set `methods' to NULL. if (sig != 'V') - _Jv_FindArrayClass (this, NULL, (_Jv_VTable *) array_vtable); + _Jv_NewArrayClass (this, NULL, (_Jv_VTable *) array_vtable); + else + arrayclass = NULL; } }; @@ -606,8 +605,8 @@ _Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader) } case '[': - return _Jv_FindArrayClass (_Jv_FindClassFromSignature (&sig[1], loader), - loader); + return _Jv_GetArrayClass (_Jv_FindClassFromSignature (&sig[1], loader), + loader); } JvFail ("couldn't understand class signature"); return NULL; // Placate compiler. -- 2.30.2