This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Static initializer elimination


Here is the famous static-initializer-elimination patch, which I am 
finally going to check in. I am pretty satisfied that it doesn't 
introduce any thread safety problems now, since it synchronizes on 
java.lang.Class to prevent concurrent modification of the class chain 
during dlopen() calls and during class registration by the interpreter. 
The other dlopen call, in SharedLibClassLoader, is already appropriatly 
synchronized.

Bryce.


2001-10-16  Bryce McKinlay  <bryce@waitaki.otago.ac.nz>

	Eliminate use of C++ static constructors.		
	* interpret.cc: Remove static Utf8Consts. Use namespace gcj. 
	* jni.cc: Likewise.
	* resolve.cc: Likewise.
	* defineclass.cc: Likewise.
	(_Jv_ClassReader::handleClassBegin): Synchronize call to 
	_Jv_RegisterClass.
	* include/jvm.h (void_signature, clinit_name, init_name, finit_name):
	Declare in namespace gcj.
	* java/lang/Class.h (Class): Remove initialization for primitive
	types.
	(friend void _Jv_InitPrimClass): This is in prims.cc.
	* prims.cc (_Jv_InitPrimClass): Do primitive type initialization
	here instead.
	(void_signature, clinit_name, init_name, finit_name): Define in 
	namespace gcj.
	(_Jv_CreateJavaVM): Call _Jv_InitThreads, _Jv_InitGC, and 
	_Jv_InitializeSyncMutex from here. Initialize Utf8 constants. 
	Initialize primitive types.
	* java/lang/natClassLoader.cc (_Jv_RegisterClasses): Don't call
	initialization routines. Don't synchronize.
	* java/lang/natRuntime.cc (_load): Synchronize on java.lang.Class
	across dlopen call.


Index: defineclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/defineclass.cc,v
retrieving revision 1.19
diff -u -r1.19 defineclass.cc
--- defineclass.cc	2001/10/07 18:02:44	1.19
+++ defineclass.cc	2001/10/16 08:28:03
@@ -41,11 +41,8 @@
 #include <java/lang/IncompatibleClassChangeError.h>
 #include <java/lang/reflect/Modifier.h>
 
-// we don't verify method names that match these.
-static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8);
-static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
+using namespace gcj;
 
-
 // these go in some separate functions, to avoid having _Jv_InitClass
 // inserted all over the place.
 static void throw_internal_error (char *msg)
@@ -934,7 +931,11 @@
   // to include references to this class.
 
   def->state = JV_STATE_PRELOADING;
-  _Jv_RegisterClass (def);
+
+  {
+    JvSynchronize sync (&java::lang::Class::class$);
+    _Jv_RegisterClass (def);
+  }
 
   if (super_class != 0)
     {
Index: interpret.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/interpret.cc,v
retrieving revision 1.26
diff -u -r1.26 interpret.cc
--- interpret.cc	2001/09/21 16:59:11	1.26
+++ interpret.cc	2001/10/16 08:28:04
@@ -37,7 +37,7 @@
 
 #include <stdlib.h>
 
-static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
+using namespace gcj;
 
 static void throw_internal_error (char *msg)
   __attribute__ ((__noreturn__));
Index: jni.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni.cc,v
retrieving revision 1.52
diff -u -r1.52 jni.cc
--- jni.cc	2001/10/05 14:23:06	1.52
+++ jni.cc	2001/10/16 08:28:04
@@ -48,6 +48,8 @@
 #include <java-interp.h>
 #include <java-threads.h>
 
+using namespace gcj;
+
 // This enum is used to select different template instantiations in
 // the invocation code.
 enum invocation_type
@@ -1501,9 +1503,6 @@
 			   jboolean)
 {
   using namespace java::lang::reflect;
-
-  // FIXME.
-  static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
 
   jobject result = NULL;
 
Index: prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.60
diff -u -r1.60 prims.cc
--- prims.cc	2001/10/10 22:25:42	1.60
+++ prims.cc	2001/10/16 08:28:04
@@ -574,22 +574,40 @@
 
 
 
-#define DECLARE_PRIM_TYPE(NAME, SIG, LEN)				\
-  _Jv_ArrayVTable _Jv_##NAME##VTable;					\
-  java::lang::Class _Jv_##NAME##Class ((jobject) #NAME,			\
-				       (jbyte) SIG, (jint) LEN,		\
-				       (jobject) &_Jv_##NAME##VTable);
-
-DECLARE_PRIM_TYPE(byte, 'B', 1);
-DECLARE_PRIM_TYPE(short, 'S', 2);
-DECLARE_PRIM_TYPE(int, 'I', 4);
-DECLARE_PRIM_TYPE(long, 'J', 8);
-DECLARE_PRIM_TYPE(boolean, 'Z', 1);
-DECLARE_PRIM_TYPE(char, 'C', 2);
-DECLARE_PRIM_TYPE(float, 'F', 4);
-DECLARE_PRIM_TYPE(double, 'D', 8);
-DECLARE_PRIM_TYPE(void, 'V', 0);
+#define DECLARE_PRIM_TYPE(NAME)			\
+  _Jv_ArrayVTable _Jv_##NAME##VTable;		\
+  java::lang::Class _Jv_##NAME##Class;
+
+DECLARE_PRIM_TYPE(byte);
+DECLARE_PRIM_TYPE(short);
+DECLARE_PRIM_TYPE(int);
+DECLARE_PRIM_TYPE(long);
+DECLARE_PRIM_TYPE(boolean);
+DECLARE_PRIM_TYPE(char);
+DECLARE_PRIM_TYPE(float);
+DECLARE_PRIM_TYPE(double);
+DECLARE_PRIM_TYPE(void);
 
+void
+_Jv_InitPrimClass (jclass cl, char *cname, char sig, int len, 
+                   _Jv_ArrayVTable *array_vtable)
+{    
+  using namespace java::lang::reflect;
+
+  // We must initialize every field of the class.  We do this in the
+  // same order they are declared in Class.h, except for fields that
+  // are initialized to NULL.
+  cl->name = _Jv_makeUtf8Const ((char *) cname, -1);
+  cl->accflags = Modifier::PUBLIC | Modifier::FINAL | Modifier::ABSTRACT;
+  cl->method_count = sig;
+  cl->size_in_bytes = len;
+  cl->vtable = JV_PRIMITIVE_VTABLE;
+  cl->state = JV_STATE_DONE;
+  cl->depth = -1;
+  if (sig != 'V')
+    _Jv_NewArrayClass (cl, NULL, (_Jv_VTable *) array_vtable);
+}
+
 jclass
 _Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader)
 {
@@ -848,10 +866,48 @@
 }
 #endif // DISABLE_GETENV_PROPERTIES
 
+namespace gcj
+{
+  _Jv_Utf8Const *void_signature;
+  _Jv_Utf8Const *clinit_name;
+  _Jv_Utf8Const *init_name;
+  _Jv_Utf8Const *finit_name;
+}
+
 jint
 _Jv_CreateJavaVM (void* /*vm_args*/)
 {
+  using namespace gcj;
+  
+  static bool init = false;
+
+  if (init)
+    return -1;
+
+  init = true;
+
   PROCESS_GCJ_PROPERTIES;
+
+  _Jv_InitThreads ();
+  _Jv_InitGC ();
+  _Jv_InitializeSyncMutex ();
+
+  /* Initialize Utf8 constants declared in jvm.h. */
+  void_signature = _Jv_makeUtf8Const ("()V", 3);
+  clinit_name = _Jv_makeUtf8Const ("<clinit>", 8);
+  init_name = _Jv_makeUtf8Const ("<init>", 6);
+  finit_name = _Jv_makeUtf8Const ("finit$", 6);
+
+  /* Initialize built-in classes to represent primitive TYPEs. */
+  _Jv_InitPrimClass (&_Jv_byteClass,    "byte",    'B', 1, &_Jv_byteVTable);
+  _Jv_InitPrimClass (&_Jv_shortClass,   "short",   'S', 2, &_Jv_shortVTable);
+  _Jv_InitPrimClass (&_Jv_intClass,     "int",     'I', 4, &_Jv_intVTable);
+  _Jv_InitPrimClass (&_Jv_longClass,    "long",    'J', 8, &_Jv_longVTable);
+  _Jv_InitPrimClass (&_Jv_booleanClass, "boolean", 'Z', 1, &_Jv_booleanVTable);
+  _Jv_InitPrimClass (&_Jv_charClass,    "char",    'C', 2, &_Jv_charVTable);
+  _Jv_InitPrimClass (&_Jv_floatClass,   "float",   'F', 4, &_Jv_floatVTable);
+  _Jv_InitPrimClass (&_Jv_doubleClass,  "double",  'D', 8, &_Jv_doubleVTable);
+  _Jv_InitPrimClass (&_Jv_voidClass,    "void",    'V', 0, &_Jv_voidVTable);
 
   // Turn stack trace generation off while creating exception objects.
   _Jv_InitClass (&java::lang::Throwable::class$);
Index: resolve.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/resolve.cc,v
retrieving revision 1.24
diff -u -r1.24 resolve.cc
--- resolve.cc	2001/10/03 07:54:34	1.24
+++ resolve.cc	2001/10/16 08:28:04
@@ -32,6 +32,8 @@
 #include <java/lang/IncompatibleClassChangeError.h>
 #include <java/lang/reflect/Modifier.h>
 
+using namespace gcj;
+
 void
 _Jv_ResolveField (_Jv_Field *field, java::lang::ClassLoader *loader)
 {
@@ -64,9 +66,6 @@
 			 jboolean,
 			 jint);
 
-
-// We need to know the name of a constructor.
-static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
 
 static void throw_incompatible_class_change_error (jstring msg)
 {
Index: include/jvm.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/jvm.h,v
retrieving revision 1.43
diff -u -r1.43 jvm.h
--- jvm.h	2001/10/15 22:42:42	1.43
+++ jvm.h	2001/10/16 08:28:04
@@ -124,6 +124,15 @@
 // FIXME: remove this define.
 #define StringClass java::lang::String::class$
 
+namespace gcj
+{
+  /* Some constants used during lookup of special class methods.  */
+  extern _Jv_Utf8Const *void_signature; /* "()V" */
+  extern _Jv_Utf8Const *clinit_name;    /* "<clinit>" */
+  extern _Jv_Utf8Const *init_name;      /* "<init>" */
+  extern _Jv_Utf8Const *finit_name;     /* "finit$", */
+};
+
 /* Type of pointer used as finalizer.  */
 typedef void _Jv_FinalizerFunc (jobject);
 
Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.45
diff -u -r1.45 natClass.cc
--- natClass.cc	2001/09/30 02:41:54	1.45
+++ natClass.cc	2001/10/16 08:28:04
@@ -60,17 +60,10 @@
 #define FieldClass java::lang::reflect::Field::class$
 #define ConstructorClass java::lang::reflect::Constructor::class$
 
-// Some constants we use to look up the class initializer.
-static _Jv_Utf8Const *void_signature = _Jv_makeUtf8Const ("()V", 3);
-static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8);
-static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
-static _Jv_Utf8Const *finit_name = _Jv_makeUtf8Const ("finit$", 6);
-// The legacy `$finit$' method name, which still needs to be
-// recognized as equivalent to the now prefered `finit$' name.
-static _Jv_Utf8Const *finit_leg_name = _Jv_makeUtf8Const ("$finit$", 7);
-
 
 
+using namespace gcj;
+
 jclass
 java::lang::Class::forName (jstring className, jboolean initialize,
                             java::lang::ClassLoader *loader)
@@ -341,9 +334,7 @@
       if (method->name == NULL
 	  || _Jv_equalUtf8Consts (method->name, clinit_name)
 	  || _Jv_equalUtf8Consts (method->name, init_name)
-	  || _Jv_equalUtf8Consts (method->name, finit_name)
-	  // Backward compatibility hack: match the legacy `$finit$' name
-	  || _Jv_equalUtf8Consts (method->name, finit_leg_name))
+	  || _Jv_equalUtf8Consts (method->name, finit_name))
 	continue;
       numMethods++;
     }
@@ -357,9 +348,7 @@
       if (method->name == NULL
 	  || _Jv_equalUtf8Consts (method->name, clinit_name)
 	  || _Jv_equalUtf8Consts (method->name, init_name)
-	  || _Jv_equalUtf8Consts (method->name, finit_name)
-	  // Backward compatibility hack: match the legacy `$finit$' name
-	  || _Jv_equalUtf8Consts (method->name, finit_leg_name))
+	  || _Jv_equalUtf8Consts (method->name, finit_name))
 	continue;
       java::lang::reflect::Method* rmethod
 	= new java::lang::reflect::Method ();
@@ -522,9 +511,7 @@
       if (method->name == NULL
 	  || _Jv_equalUtf8Consts (method->name, clinit_name)
 	  || _Jv_equalUtf8Consts (method->name, init_name)
-	  || _Jv_equalUtf8Consts (method->name, finit_name)
-	  // Backward compatibility hack: match the legacy `$finit$' name
-	  || _Jv_equalUtf8Consts (method->name, finit_leg_name))
+	  || _Jv_equalUtf8Consts (method->name, finit_name))
 	continue;
       // Only want public methods.
       if (! java::lang::reflect::Modifier::isPublic (method->accflags))
Index: java/lang/natClassLoader.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClassLoader.cc,v
retrieving revision 1.37
diff -u -r1.37 natClassLoader.cc
--- natClassLoader.cc	2001/09/21 16:59:12	1.37
+++ natClassLoader.cc	2001/10/16 08:28:05
@@ -175,7 +175,6 @@
   klass->notifyAll ();
 }
 
-
 // This is the findClass() implementation for the System classloader. It is 
 // the only native method in VMClassLoader, so we define it here.
 jclass
@@ -419,24 +418,13 @@
 }
 
 // This function is called many times during startup, before main() is
-// run.  We do our runtime initialization here the very first time we
-// are called.  At that point in time we know for certain we are
-// running single-threaded, so we don't need to lock when modifying
-// `init'.  CLASSES is NULL-terminated.
+// run.  At that point in time we know for certain we are running 
+// single-threaded, so we don't need to lock when adding classes to the 
+// class chain.  At all other times, the caller should synchronize on
+// Class::class$.
 void
 _Jv_RegisterClasses (jclass *classes)
 {
-  static bool init = false;
-
-  if (! init)
-    {
-      init = true;
-      _Jv_InitThreads ();
-      _Jv_InitGC ();
-      _Jv_InitializeSyncMutex ();
-    }
-
-  JvSynchronize sync (&ClassClass);
   for (; *classes; ++classes)
     {
       jclass klass = *classes;
Index: java/lang/natRuntime.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natRuntime.cc,v
retrieving revision 1.19
diff -u -r1.19 natRuntime.cc
--- natRuntime.cc	2001/10/10 22:25:43	1.19
+++ natRuntime.cc	2001/10/16 08:28:05
@@ -138,8 +138,15 @@
 #endif
   jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]);
   buf[offset + total] = '\0';
+  lt_dlhandle h;
   // FIXME: make sure path is absolute.
-  lt_dlhandle h = do_search ? lt_dlopenext (buf) : lt_dlopen (buf);
+  {
+    // Synchronize on java.lang.Class. This is to protect the class chain from
+    // concurrent modification by class registration calls which may be run
+    // during the dlopen().
+    JvSynchronize sync (&java::lang::Class::class$);
+    h = do_search ? lt_dlopenext (buf) : lt_dlopen (buf);
+  }
   if (h == NULL)
     {
       const char *msg = lt_dlerror ();

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]