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]
Other format: [Raw text]

Patch: Serialization merge from GNU Classpath


This patch merges the latest serialization code from GNU Classpath into libgcj. Although there are a few things I'm not entirely happy with in the current classpath implementation, the benefits of merging the two codebases outweigh those concerns, and it will be better to fix these things in general rather than making fixes that are only in libgcj. Once I check in a much smaller patch to Classpath, we'll have a 100% merged serialization implementation for the first time!

As a side-effect, this also fixes a long-standing bug where final fields in libgcj could be set via reflection (we couldn't fix this bug because it would break the old serialization code).

We have several new mauve PASSes with this patch:

--- batch_run.clean.out 2005-02-21 12:17:58.000000000 -0500
+++ batch_run.patched.out 2005-02-21 11:43:52.000000000 -0500
@@ -5497,10 +5497,10 @@
PASS: gnu.testlet.java.io.ObjectInputOutput.OutputTest: Unserializable: gnu.testlet.java.io.ObjectInputOutput.Test$BadField (x = 0, y = 0, o = null) (number 1)
PASS: gnu.testlet.java.io.ObjectInputOutput.SerTest (number 1)
PASS: gnu.testlet.java.io.ObjectInputOutput.SerTest (number 2)
-FAIL: gnu.testlet.java.io.ObjectInputOutput.Deserializable: Wrong exception (number 1)
+PASS: gnu.testlet.java.io.ObjectInputOutput.Deserializable: Deserialize gnu.testlet.java.io.ObjectInputOutput.Deserializable$Serialized1 (number 1)
FAIL: gnu.testlet.java.io.ObjectInputOutput.Deserializable: Was expecting an InvalidClassException (number 1)
PASS: gnu.testlet.java.io.ObjectInputOutput.ExtTest (number 1)
-FAIL: gnu.testlet.java.io.ObjectInputOutput.ExtTest (number 2)
+PASS: gnu.testlet.java.io.ObjectInputOutput.ExtTest (number 2)
PASS: gnu.testlet.java.io.ObjectStreamClass.ProxyTest: zero serialVersionUID (number 1)
PASS: gnu.testlet.java.io.ObjectStreamClass.ProxyTest: zero ObjectStreamFields (number 1)
PASS: gnu.testlet.java.io.ObjectStreamClass.ProxyTest: getField(any) returns null (number 1)
@@ -6367,10 +6367,10 @@
PASS: gnu.testlet.java.lang.Class.init (number 13)
FAIL: gnu.testlet.java.lang.Class.init (number 14)
PASS: gnu.testlet.java.lang.Class.init (number 15)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface java.lang.Cloneable (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface java.lang.Comparable (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface java.io.Serializable (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface java.io.Externalizable (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface java.lang.Cloneable (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface java.lang.Comparable (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface java.io.Serializable (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface java.io.Externalizable (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.String (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.Number (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.Boolean (number 1)
@@ -6382,33 +6382,33 @@
PASS: gnu.testlet.java.lang.Class.serialization: class java.text.DateFormat (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.awt.Point (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.awt.Rectangle (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.awt.geom.Rectangle2D (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.awt.geom.Rectangle2D$Double (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.awt.geom.Line2D (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.awt.geom.Arc2D (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.awt.geom.RoundRectangle2D (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.awt.Graphics2D (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.awt.geom.Rectangle2D (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.awt.geom.Rectangle2D$Double (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.awt.geom.Line2D (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.awt.geom.Arc2D (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.awt.geom.RoundRectangle2D (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.awt.Graphics2D (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class javax.swing.table.DefaultTableModel (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface java.awt.LayoutManager (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.lang.reflect.Array (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.lang.Object (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface java.awt.LayoutManager (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.reflect.Array (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.Object (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.Class (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.Throwable (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.io.IOException (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.lang.Void (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.Void (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.io.ObjectStreamClass (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface java.util.Collection (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface java.util.Set (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface java.util.SortedSet (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: boolean (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: byte (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: short (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: char (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: int (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: long (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: float (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: double (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: void (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface java.util.Collection (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface java.util.Set (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface java.util.SortedSet (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: boolean (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: byte (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: short (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: char (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: int (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: long (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: float (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: double (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: void (number 1)
PASS: gnu.testlet.java.lang.Double.DoubleTest: Error: test_Basics failed - 2 (number 1)
PASS: gnu.testlet.java.lang.Double.DoubleTest: Error: test_Basics failed - 3 (number 1)
PASS: gnu.testlet.java.lang.Double.DoubleTest: Error: test_Basics failed - 4 (number 1)


Bryce

2005-02-21  Bryce McKinlay  <mckinlay@redhat.com>

	Merge serialization from GNU Classpath.
	* gcj/method.h: Add missing #includes.
	* java/io/ObjectInputStream.java (readClassDescriptor): Check for 
	primitive class IDs on the stream here...
	(resolveClass): ...not here.
	* java/io/ObjectStreamField.java: Use VMObjectStream class calls to set
	fields.
	* java/io/VMObjectStreamClass.java (setDoubleNative, setFloatNative,
	setLongNative, setIntNative, setShortNative, setCharNative,
	setByteNative, setBooleanNative, setObjectNative): New native methods.
	* java/io/natObjectInputStream.cc (allocateObject): Add new parameters
	from Classpath's version. Use _Jv_FromReflectedConstructor(). Call
	the constructor here.
	(callConstructor): Removed.
	(getCallersClassLoader): Removed.
	* java/lang/reflect/Field.java (setByte, setShort, setInt, setLong,
	setFloat, setDouble, setChar, setBoolean): Add 'checkFinal' parameter
	to control whether setting final field values is permitted. Call
	getAddr() with checkFinal parameter instead of setAddr().
	* java/lang/reflect/natField.cc (getType): Lookup and resolve field
	only if not done already.
	(getAddr): Add checkFinal parameter. Do the final field check only if
	checkFinal is set.
	(setAddr): Removed.

2005-02-21  Mark Wielaard  <mark@klomp.org>

	# Fixes bug #11957
	* java/io/ObjectInputStream.java (resolveClass): Don't check "void"
	twice.
	
2005-02-21  Mark Wielaard  <mark@klomp.org>

	Fixes bug #11618.
	* java/io/ObjectInputStream.java (readClassDescriptor): Handle classes
	without a super class and us ObjectStreamClass.lookupForClassObject().
	(resolveClass): Check for primitive types.
	(lookupClass): Return null when argument is null.

2005-02-21  Jeroen Frijters  <jeroen@frijters.net>

	* java/io/ObjectInputStream.java
	(readObject): Fix to consume TC_ENDBLOCKDATA after readExternal.

2005-02-21  Jeroen Frijters  <jeroen@frijters.net>

	* java/io/ObjectOutputStream.java
	(writeObject, callWriteMethod): Replaced reflection with accessing
	cached info in ObjectStreamClass.
	(getMethod): Removed.
	* java/io/ObjectStreamClass.java
	(findMethod): Added check to make sure the method found has the
	right modifiers.
	(cacheMethods): Added writeReplace and writeObject methods.
	(setFlags): Look at new writeObjectMethod field instead of doing
	reflection again.
	(writeReplaceMethod): New field.
	(writeObjectMethod): New field.

2005-02-21  Guilhem Lavaux  <guilhem@kaffe.org>
	Jeroen Frijters  <jeroen@frijters.net>

	* java/io/ObjectInputStream.java
	(newObject): Changed prototype. Get a constructor reflect object
	directly.
	(callConstructor): Removed.
	(allocateObject): Changed prototype.
	(readClassDescriptor): Build the constructor reflection directly.
	(readObject): Invoke newObject using the new prototype.

	* java/io/ObjectStreamClass.java
	(firstNonSerializableParent): Removed.
	(firstNonSerializableParentConstructor): Added.	


Index: gcj/method.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/method.h,v
retrieving revision 1.6
diff -u -r1.6 method.h
--- gcj/method.h	7 Mar 2000 19:55:24 -0000	1.6
+++ gcj/method.h	21 Feb 2005 20:48:07 -0000
@@ -12,6 +12,8 @@
 #define __GCJ_METHOD_H__
 
 #include <java/lang/Class.h>
+#include <java/lang/reflect/Constructor.h>
+#include <java/lang/reflect/Method.h>
 
 extern inline jmethodID
 _Jv_FromReflectedMethod (java::lang::reflect::Method *method)
Index: java/io/ObjectInputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectInputStream.java,v
retrieving revision 1.40
diff -u -r1.40 ObjectInputStream.java
--- java/io/ObjectInputStream.java	20 Feb 2005 21:18:30 -0000	1.40
+++ java/io/ObjectInputStream.java	21 Feb 2005 20:48:07 -0000
@@ -43,6 +43,7 @@
 import gnu.java.io.ObjectIdentityWrapper;
 
 import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -122,15 +123,6 @@
    */
   public final Object readObject() throws ClassNotFoundException, IOException
   {
-	if (callersClassLoader == null)
-	  {
-		callersClassLoader = getCallersClassLoader ();
-		if (Configuration.DEBUG && dump)
-		  {
-			dumpElementln ("CallersClassLoader = " + callersClassLoader);
-		  }
-	  }
-	
     if (this.useSubclassMethod)
       return readObjectOverride();
 
@@ -272,7 +264,7 @@
 	      readArrayElements(array, componentType);
 	      if(dump)
 	        for (int i = 0, len = Array.getLength(array); i < len; i++)
-			  dumpElementln("  ELEMENT[" + i + "]=" + Array.get(array, i));
+		  dumpElementln("  ELEMENT[" + i + "]=" + Array.get(array, i));
 	      ret_val = processResolution(null, array, handle);
 	      break;
 	    }
@@ -302,13 +294,18 @@
 		  obj.readExternal(this);
 		  
 		  if (read_from_blocks)
-		    setBlockDataMode(oldmode);
+                    {
+		      setBlockDataMode(oldmode);
+                      if (!oldmode)
+			if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
+			    throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
+                    }
 		  
 		  ret_val = processResolution(osc, obj, handle);
 		  break;
 		} // end if (osc.realClassIsExternalizable)
 
-	      Object obj = newObject(clazz, osc.firstNonSerializableParent);
+	      Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
 	      
 	      int handle = assignNewHandle(obj);
 	      Object prevObject = this.currentObject;
@@ -399,8 +396,6 @@
 	setBlockDataMode(old_mode);
 	
 	this.isDeserializing = was_deserializing;
-
-	depth -= 2;
 	
 	depth -= 2;
 	
@@ -506,7 +501,8 @@
 						  flags, fields);
     assignNewHandle(osc);
 
-    ClassLoader currentLoader = currentLoader();
+    if (callersClassLoader == null)
+      callersClassLoader = currentLoader();
 	      
     for (int i = 0; i < field_count; i++)
       {
@@ -527,12 +523,40 @@
 	  class_name = String.valueOf(type_code);
 		  
 	fields[i] =
-	  new ObjectStreamField(field_name, class_name, currentLoader);
+	  new ObjectStreamField(field_name, class_name, callersClassLoader);
       }
 	      
     /* Now that fields have been read we may resolve the class
      * (and read annotation if needed). */
-    Class clazz = resolveClass(osc);
+    Class clazz;
+    try
+      {
+	clazz = resolveClass(osc);
+      }
+    catch (ClassNotFoundException cnfe)
+      {
+	// Maybe it was an primitive class?
+	if (name.equals("void"))
+	  clazz = Void.TYPE;
+	else if (name.equals("boolean"))
+	  clazz = Boolean.TYPE;
+	else if (name.equals("byte"))
+	  clazz = Byte.TYPE;
+	else if (name.equals("short"))
+	  clazz = Short.TYPE;
+	else if (name.equals("char"))
+	  clazz = Character.TYPE;
+	else if (name.equals("int"))
+	  clazz = Integer.TYPE;
+	else if (name.equals("long"))
+	  clazz = Long.TYPE;
+	else if (name.equals("float"))
+	  clazz = Float.TYPE;
+	else if (name.equals("double"))
+	  clazz = Double.TYPE;
+	else
+	  throw cnfe;
+      }
 
     boolean oldmode = setBlockDataMode(true);
     osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
@@ -542,16 +566,45 @@
     // find the first non-serializable, non-abstract
     // class in clazz's inheritance hierarchy
     Class first_nonserial = clazz.getSuperclass();
-    while (Serializable.class.isAssignableFrom(first_nonserial)
-	|| Modifier.isAbstract(first_nonserial.getModifiers()))
+    // Maybe it is a primitive class, those don't have a super class,
+    // or Object itself.  Otherwise we can keep getting the superclass
+    // till we hit the Object class, or some other non-serializable class.
+
+    if (first_nonserial == null)
+      first_nonserial = clazz;
+    else
+      while (Serializable.class.isAssignableFrom(first_nonserial)
+	     || Modifier.isAbstract(first_nonserial.getModifiers()))
 	first_nonserial = first_nonserial.getSuperclass();
 
-    osc.firstNonSerializableParent = first_nonserial;
+    final Class local_constructor_class = first_nonserial;
+
+    osc.firstNonSerializableParentConstructor =
+        (Constructor)AccessController.doPrivileged(new PrivilegedAction()
+          {
+            public Object run()
+            {
+              try
+                {
+                  Constructor c = local_constructor_class.
+                                    getDeclaredConstructor(new Class[0]);
+                  if (Modifier.isPrivate(c.getModifiers()))
+                    return null;
+                  return c;
+                }
+              catch (NoSuchMethodException e)
+                {
+                  // error will be reported later, in newObject()
+                  return null;
+                }
+            }
+          });
+
     osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
     osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
 
     ObjectStreamField[] stream_fields = osc.fields;
-    ObjectStreamField[] real_fields = ObjectStreamClass.lookup(clazz).fields;
+    ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
     ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
 
     int stream_idx = 0;
@@ -717,6 +770,15 @@
   protected Class resolveClass(ObjectStreamClass osc)
     throws ClassNotFoundException, IOException
   {
+    if (callersClassLoader == null)
+      {
+	callersClassLoader = currentLoader ();
+	if (Configuration.DEBUG && dump)
+	  {
+	    dumpElementln ("CallersClassLoader = " + callersClassLoader);
+	  }
+      }
+
     return Class.forName(osc.getName(), true, callersClassLoader);
   }
 
@@ -750,8 +812,10 @@
    */
   private ObjectStreamClass lookupClass(Class clazz)
   {
-    ObjectStreamClass oclazz;
+    if (clazz == null)
+      return null;
 
+    ObjectStreamClass oclazz;
     oclazz = (ObjectStreamClass)classLookupTable.get(clazz);
     if (oclazz == null)
       return ObjectStreamClass.lookup(clazz);
@@ -1767,14 +1831,14 @@
 
   // returns a new instance of REAL_CLASS that has been constructed
   // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
-  private Object newObject (Class real_class, Class constructor_class)
-    throws ClassNotFoundException
+  private Object newObject (Class real_class, Constructor constructor)
+    throws ClassNotFoundException, IOException
   {
+    if (constructor == null)
+        throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName()); 
     try
       {
-	Object obj = allocateObject (real_class);
-	callConstructor (constructor_class, obj);
-	return obj;
+	return allocateObject(real_class, constructor.getDeclaringClass(), constructor);
       }
     catch (InstantiationException e)
       {
@@ -1810,8 +1874,6 @@
    * @return The current class loader in the calling stack.
    */
   private static native ClassLoader currentClassLoader (SecurityManager sm);
-  
-  private native ClassLoader getCallersClassLoader();
 
   private void callReadMethod (Method readObject, Class klass, Object obj)
     throws ClassNotFoundException, IOException
@@ -1844,11 +1906,9 @@
     prereadFields = null;
   }
     
-  private native Object allocateObject (Class clazz)
+  private native Object allocateObject(Class clazz, Class constr_clazz, Constructor constructor)
     throws InstantiationException;
 
-  private native void callConstructor (Class clazz, Object obj);
-
   private static final int BUFFER_SIZE = 1024;
 
   private DataInputStream realInputStream;
@@ -1870,9 +1930,8 @@
   private Hashtable classLookupTable;
   private GetField prereadFields;
 
-  private static boolean dump = false && Configuration.DEBUG;
-
   private ClassLoader callersClassLoader;
+  private static boolean dump;
 
   // The nesting depth for debugging output
   private int depth = 0;
Index: java/io/ObjectOutputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectOutputStream.java,v
retrieving revision 1.31
diff -u -r1.31 ObjectOutputStream.java
--- java/io/ObjectOutputStream.java	25 Nov 2004 03:47:02 -0000	1.31
+++ java/io/ObjectOutputStream.java	21 Feb 2005 20:48:07 -0000
@@ -250,6 +250,11 @@
 		break;
 	      }
 
+	    Class clazz = obj.getClass();
+	    ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
+	    if (osc == null)
+	      throw new NotSerializableException(clazz.getName());
+	    
 	    if ((replacementEnabled || obj instanceof Serializable)
 		&& ! replaceDone)
 	      {
@@ -257,19 +262,11 @@
 		
 		if (obj instanceof Serializable)
 		  {
-		    Method m = null;
 		    try
 		      {
-			Class classArgs[] = {};
-			m = getMethod(obj.getClass(), "writeReplace",
-				      classArgs);
-			// m can't be null by definition since an
-			// exception would have been thrown so a check
-			// for null is not needed.
-			obj = m.invoke(obj, new Object[] {});
-		      }
-		    catch (NoSuchMethodException ignore)
-		      {
+                        Method m = osc.writeReplaceMethod;
+                        if (m != null)
+                            obj = m.invoke(obj, new Object[0]);
 		      }
 		    catch (IllegalAccessException ignore)
 		      {
@@ -294,11 +291,6 @@
 		break;
 	      }
 
-	    Class clazz = obj.getClass();
-	    ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
-	    if (osc == null)
-	      throw new NotSerializableException(clazz.getName());
-	    
 	    if (clazz.isArray ())
 	      {
 		realOutput.writeByte(TC_ARRAY);
@@ -347,8 +339,8 @@
 		    fieldsAlreadyWritten = false;
 		    if (currentObjectStreamClass.hasWriteMethod())
 		      {
-				if (dump)
-				  dumpElementln ("WRITE METHOD CALLED FOR: " + obj);
+			if (dump)
+			  dumpElementln ("WRITE METHOD CALLED FOR: " + obj);
 			setBlockDataMode(true);
 			callWriteMethod(obj, currentObjectStreamClass);
 			setBlockDataMode(false);
@@ -358,10 +350,10 @@
 		      }
 		    else
 		      {
-				if (dump)
-				  dumpElementln ("WRITE FIELDS CALLED FOR: " + obj);
-				writeFields(obj, currentObjectStreamClass);
-			  }
+			if (dump)
+			  dumpElementln ("WRITE FIELDS CALLED FOR: " + obj);
+			writeFields(obj, currentObjectStreamClass);
+		      }
 		  }
 
 		this.currentObject = prevObject;
@@ -1261,18 +1253,11 @@
   private void callWriteMethod(Object obj, ObjectStreamClass osc)
     throws IOException
   {
-    Class klass = osc.forClass();
     currentPutField = null;
     try
       {
-	Class classArgs[] = {ObjectOutputStream.class};
-	Method m = getMethod(klass, "writeObject", classArgs);
-	Object args[] = {this};
-	m.invoke(obj, args);	
-      }
-    catch (NoSuchMethodException nsme)
-      {
-	// Nothing.
+        Object args[] = {this};
+        osc.writeObjectMethod.invoke(obj, args);
       }
     catch (InvocationTargetException x)
       {
@@ -1285,7 +1270,8 @@
 
 	IOException ioe
 	  = new IOException("Exception thrown from writeObject() on " +
-			    klass + ": " + exception.getClass().getName());
+			    osc.forClass().getName() + ": " +
+                            exception.getClass().getName());
 	ioe.initCause(exception);
 	throw ioe;
       }
@@ -1293,7 +1279,8 @@
       {
 	IOException ioe
 	  = new IOException("Failure invoking writeObject() on " +
-			    klass + ": " + x.getClass().getName());
+			    osc.forClass().getName() + ": " +
+			    x.getClass().getName());
 	ioe.initCause(x);
 	throw ioe;
       }
@@ -1535,15 +1522,6 @@
       }
   }
 
-  private Method getMethod (Class klass, String name, Class[] args)
-    throws java.lang.NoSuchMethodException
-  {
-    final Method m = klass.getDeclaredMethod(name, args);
-    setAccessible.setMember(m);
-    AccessController.doPrivileged(setAccessible);
-    return m;
-  }
-
   private void dumpElementln (String msg)
   {
     for (int i = 0; i < depth; i++)
Index: java/io/ObjectStreamClass.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectStreamClass.java,v
retrieving revision 1.24
diff -u -r1.24 ObjectStreamClass.java
--- java/io/ObjectStreamClass.java	9 Oct 2004 10:22:25 -0000	1.24
+++ java/io/ObjectStreamClass.java	21 Feb 2005 20:48:07 -0000
@@ -452,27 +452,33 @@
   }
 
   private Method findMethod(Method[] methods, String name, Class[] params,
-			    Class returnType)
+			    Class returnType, boolean mustBePrivate)
   {
 outer:
-    for(int i = 0; i < methods.length; i++)
+    for (int i = 0; i < methods.length; i++)
     {
-	if(methods[i].getName().equals(name) &&
-	   methods[i].getReturnType() == returnType)
+	final Method m = methods[i];
+        int mods = m.getModifiers();
+        if (Modifier.isStatic(mods)
+            || (mustBePrivate && !Modifier.isPrivate(mods)))
+        {
+            continue;
+        }
+
+	if (m.getName().equals(name)
+	   && m.getReturnType() == returnType)
 	{
-	    Class[] mp = methods[i].getParameterTypes();
-	    if(mp.length == params.length)
+	    Class[] mp = m.getParameterTypes();
+	    if (mp.length == params.length)
 	    {
-		for(int j = 0; j < mp.length; j++)
+		for (int j = 0; j < mp.length; j++)
 		{
-		    if(mp[j] != params[j])
+		    if (mp[j] != params[j])
 		    {
 			continue outer;
 		    }
 		}
-		final Method m = methods[i];
-		SetAccessibleAction setAccessible = new SetAccessibleAction(m);
-		AccessController.doPrivileged(setAccessible);
+		AccessController.doPrivileged(new SetAccessibleAction(m));
 		return m;
 	    }
 	}
@@ -485,9 +491,14 @@
     Method[] methods = forClass().getDeclaredMethods();
     readObjectMethod = findMethod(methods, "readObject",
 				  new Class[] { ObjectInputStream.class },
-				  Void.TYPE);
+				  Void.TYPE, true);
+    writeObjectMethod = findMethod(methods, "writeObject",
+                                   new Class[] { ObjectOutputStream.class },
+                                   Void.TYPE, true);
     readResolveMethod = findMethod(methods, "readResolve",
-				   new Class[0], Object.class);
+				   new Class[0], Object.class, false);
+    writeReplaceMethod = findMethod(methods, "writeReplace",
+                                    new Class[0], Object.class, false);
   }
 
   private ObjectStreamClass(Class cl)
@@ -517,20 +528,8 @@
       // only set this bit if CL is NOT Externalizable
       flags |= ObjectStreamConstants.SC_SERIALIZABLE;
 
-    try
-      {
-	Method writeMethod = cl.getDeclaredMethod("writeObject",
-						  writeMethodArgTypes);
-	int modifiers = writeMethod.getModifiers();
-
-	if (writeMethod.getReturnType() == Void.TYPE
-	    && Modifier.isPrivate(modifiers)
-	    && !Modifier.isStatic(modifiers))
-	  flags |= ObjectStreamConstants.SC_WRITE_METHOD;
-      }
-    catch(NoSuchMethodException oh_well)
-      {
-      }
+    if (writeObjectMethod != null)
+      flags |= ObjectStreamConstants.SC_WRITE_METHOD;
   }
 
 
@@ -851,11 +850,11 @@
     {
 	return (Externalizable)constructor.newInstance(null);
     }
-    catch(Throwable t)
+    catch(Exception x)
     {
 	throw (InvalidClassException)
 	    new InvalidClassException(clazz.getName(),
-		     "Unable to instantiate").initCause(t);
+		     "Unable to instantiate").initCause(x);
     }
   }
 
@@ -884,10 +883,12 @@
 
   Method readObjectMethod;
   Method readResolveMethod;
+  Method writeReplaceMethod;
+  Method writeObjectMethod;
   boolean realClassIsSerializable;
   boolean realClassIsExternalizable;
   ObjectStreamField[] fieldMapping;
-  Class firstNonSerializableParent;
+  Constructor firstNonSerializableParentConstructor;
   private Constructor constructor;  // default constructor for Externalizable
 
   boolean isProxyClass = false;
@@ -896,34 +897,33 @@
   // but it will avoid showing up as a discrepancy when comparing SUIDs.
   private static final long serialVersionUID = -6120832682080437368L;
 
-}
 
-
-// interfaces are compared only by name
-class InterfaceComparator implements Comparator
-{
-  public int compare(Object o1, Object o2)
+  // interfaces are compared only by name
+  private static final class InterfaceComparator implements Comparator
   {
-    return ((Class) o1).getName().compareTo(((Class) o2).getName());
+    public int compare(Object o1, Object o2)
+    {
+      return ((Class) o1).getName().compareTo(((Class) o2).getName());
+    }
   }
-}
 
 
-// Members (Methods and Constructors) are compared first by name,
-// conflicts are resolved by comparing type signatures
-class MemberComparator implements Comparator
-{
-  public int compare(Object o1, Object o2)
+  // Members (Methods and Constructors) are compared first by name,
+  // conflicts are resolved by comparing type signatures
+  private static final class MemberComparator implements Comparator
   {
-    Member m1 = (Member) o1;
-    Member m2 = (Member) o2;
+    public int compare(Object o1, Object o2)
+    {
+      Member m1 = (Member) o1;
+      Member m2 = (Member) o2;
 
-    int comp = m1.getName().compareTo(m2.getName());
+      int comp = m1.getName().compareTo(m2.getName());
 
-    if (comp == 0)
-      return TypeSignature.getEncodingOfMember(m1).
-	compareTo(TypeSignature.getEncodingOfMember(m2));
-    else
-      return comp;
+      if (comp == 0)
+        return TypeSignature.getEncodingOfMember(m1).
+	  compareTo(TypeSignature.getEncodingOfMember(m2));
+      else
+        return comp;
+    }
   }
 }
Index: java/io/ObjectStreamField.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectStreamField.java,v
retrieving revision 1.12
diff -u -r1.12 ObjectStreamField.java
--- java/io/ObjectStreamField.java	25 Sep 2004 09:47:45 -0000	1.12
+++ java/io/ObjectStreamField.java	21 Feb 2005 20:48:10 -0000
@@ -367,109 +367,46 @@
 
   final void setBooleanField(Object obj, boolean val)
   {
-    try
-      {
-	field.setBoolean(obj, val);
-      }
-    catch(IllegalAccessException x)
-      {
-	throw new InternalError(x.getMessage());
-      }
+    VMObjectStreamClass.setBooleanNative(field, obj, val);  
   }
 
   final void setByteField(Object obj, byte val)
   {
-    try
-      {
-	field.setByte(obj, val);
-      }
-    catch(IllegalAccessException x)
-      {
-	throw new InternalError(x.getMessage());
-      }
+    VMObjectStreamClass.setByteNative(field, obj, val);
   }
   
   final void setCharField(Object obj, char val)
   {
-    try
-      {
-	field.setChar(obj, val);
-      }
-    catch(IllegalAccessException x)
-      {
-	throw new InternalError(x.getMessage());
-      }
+    VMObjectStreamClass.setCharNative(field, obj, val);
   }
   
   final void setShortField(Object obj, short val)
   {
-    try
-      {
-	field.setShort(obj, val);
-      }
-    catch(IllegalAccessException x)
-      {
-	throw new InternalError(x.getMessage());
-      }
+    VMObjectStreamClass.setShortNative(field, obj, val);
   }
 
   final void setIntField(Object obj, int val)
   {
-    try
-      {
-	field.setInt(obj, val);
-      }
-    catch(IllegalAccessException x)
-      {
-	throw new InternalError(x.getMessage());
-      }
+    VMObjectStreamClass.setIntNative(field, obj, val);
   }
   
   final void setLongField(Object obj, long val)
   {
-    try
-      {
-	field.setLong(obj, val);
-      }
-    catch(IllegalAccessException x)
-      {
-	throw new InternalError(x.getMessage());
-      }
+    VMObjectStreamClass.setLongNative(field, obj, val);
   }
   
   final void setFloatField(Object obj, float val)
   {
-    try
-      {
-	field.setFloat(obj, val);
-      }
-    catch(IllegalAccessException x)
-      {
-	throw new InternalError(x.getMessage());
-      }
+    VMObjectStreamClass.setFloatNative(field, obj, val);
   }
   
   final void setDoubleField(Object obj, double val)
   {
-    try
-      {
-	field.setDouble(obj, val);
-      }
-    catch(IllegalAccessException x)
-      {
-	throw new InternalError(x.getMessage());
-      }
+    VMObjectStreamClass.setDoubleNative(field, obj, val);
   }
   
   final void setObjectField(Object obj, Object val)
   { 
-    try
-      {
-	field.set(obj, val);
-      }
-    catch(IllegalAccessException x)
-      {
-	throw new InternalError(x.getMessage());
-      }
+    VMObjectStreamClass.setObjectNative(field, obj, val);
   }
 }
Index: java/io/VMObjectStreamClass.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/VMObjectStreamClass.java,v
retrieving revision 1.1
diff -u -r1.1 VMObjectStreamClass.java
--- java/io/VMObjectStreamClass.java	20 Jan 2003 06:46:28 -0000	1.1
+++ java/io/VMObjectStreamClass.java	21 Feb 2005 20:48:10 -0000
@@ -38,7 +38,7 @@
 
 package java.io;
 
-import java.lang.reflect.Method;
+import java.lang.reflect.Field;
 
 final class VMObjectStreamClass
 {
@@ -47,4 +47,94 @@
     * (a.k.a. <clinit>).
     */
   static native boolean hasClassInitializer (Class clazz);
+
+  /**
+   * Sets the value of the specified "double" field, allowing final values 
+   * to be assigned.
+   *
+   * @param field Field to set the value.
+   * @param obj Instance which will have its field set.
+   * @param val Value to put in the field.
+   */
+  static native void setDoubleNative(Field field, Object obj, double val);
+
+  /**
+   * Sets the value of the specified "float" field, allowing final values 
+   * to be assigned.
+   *
+   * @param field Field to set the value.
+   * @param obj Instance which will have its field set.
+   * @param val Value to put in the field.
+   */
+  static native void setFloatNative(Field field, Object obj, float val);
+
+  /**
+   * Sets the value of the specified "long" field, allowing final values 
+   * to be assigned.
+   *
+   * @param field Field to set the value.
+   * @param obj Instance which will have its field set.
+   * @param val Value to put in the field.
+   */
+  static native void setLongNative(Field field, Object obj, long val);
+  
+  /**
+   * Sets the value of the specified "int" field, allowing final values 
+   * to be assigned.
+   *
+   * @param field Field to set the value.
+   * @param obj Instance which will have its field set.
+   * @param val Value to put in the field.
+   */
+  static native void setIntNative(Field field, Object obj, int val);
+  
+  /**
+   * Sets the value of the specified "short" field, allowing final values 
+   * to be assigned.
+   *
+   * @param field Field to set the value.
+   * @param obj Instance which will have its field set.
+   * @param val Value to put in the field.
+   */
+  static native void setShortNative(Field field, Object obj, short val);
+
+  /**
+   * Sets the value of the specified "char" field, allowing final values 
+   * to be assigned.
+   *
+   * @param field Field to set the value.
+   * @param obj Instance which will have its field set.
+   * @param val Value to put in the field.
+   */
+  static native void setCharNative(Field field, Object obj, char val);
+
+  /**
+   * Sets the value of the specified "byte" field, allowing final values 
+   * to be assigned.
+   *
+   * @param field Field to set the value.
+   * @param obj Instance which will have its field set.
+   * @param val Value to put in the field.
+   */
+  static native void setByteNative(Field field, Object obj, byte val);
+
+  /**
+   * Sets the value of the specified "boolean" field, allowing final values 
+   * to be assigned.
+   *
+   * @param field Field to set the value.
+   * @param obj Instance which will have its field set.
+   * @param val Value to put in the field.
+   */
+  static native void setBooleanNative(Field field, Object obj, boolean val);
+
+  /**
+   * Sets the value of the specified object field, allowing final values 
+   * to be assigned.
+   *
+   * @param field Field to set the value.
+   * @param obj Instance which will have its field set.
+   * @param val Value to put in the field.
+   */
+  static native void setObjectNative(Field field, Object obj, Object val);
 }
Index: java/io/natObjectInputStream.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/natObjectInputStream.cc,v
retrieving revision 1.8
diff -u -r1.8 natObjectInputStream.cc
--- java/io/natObjectInputStream.cc	21 Jun 2004 16:52:14 -0000	1.8
+++ java/io/natObjectInputStream.cc	21 Feb 2005 20:48:10 -0000
@@ -12,6 +12,7 @@
 
 #include <gcj/cni.h>
 #include <jvm.h>
+#include <gcj/method.h>
 
 #include <java/io/ObjectInputStream$GetField.h>
 #include <java/io/ObjectInputStream.h>
@@ -21,6 +22,8 @@
 #include <java/lang/reflect/Method.h>
 #include <java/lang/ArrayIndexOutOfBoundsException.h>
 #include <java/lang/SecurityManager.h>
+#include <java/lang/reflect/Constructor.h>
+#include <java/lang/reflect/Method.h>
 
 #ifdef DEBUG
 #include <java/lang/System.h>
@@ -28,7 +31,8 @@
 #endif
 
 jobject
-java::io::ObjectInputStream::allocateObject (jclass klass)
+java::io::ObjectInputStream::allocateObject (jclass klass, jclass,
+  ::java::lang::reflect::Constructor *ctr)
 {
   jobject obj = NULL;
   using namespace java::lang::reflect;
@@ -41,21 +45,15 @@
       else
 	{
 	  obj = _Jv_AllocObject (klass);
-	}
+	}	
     }
   catch (jthrowable t)
     {
       return NULL;
     }
 
-  return obj;
-}
-
+  jmethodID meth = _Jv_FromReflectedConstructor (ctr);
 
-void 
-java::io::ObjectInputStream::callConstructor (jclass klass, jobject obj)
-{ 
-  jstring init_name = JvNewStringLatin1 ("<init>");
   // This is a bit inefficient, and a bit of a hack, since we don't
   // actually use the Method and since what is returned isn't
   // technically a Method.  We can't use Method.invoke as it looks up
@@ -63,36 +61,12 @@
   JArray<jclass> *arg_types
     = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
 					   NULL);
-  java::lang::reflect::Method *m = klass->getPrivateMethod (init_name,
-							    arg_types);
+
   // We lie about this being a constructor.  If we put `true' here
   // then _Jv_CallAnyMethodA would try to allocate the object for us.
-  jmethodID meth = (jmethodID) ((char *) (klass->methods)
-				+ m->offset);
   _Jv_CallAnyMethodA (obj, JvPrimClass (void), meth, false, arg_types, NULL);
-}
 
-java::lang::ClassLoader* 
-java::io::ObjectInputStream::getCallersClassLoader ()
-{
-  java::lang::ClassLoader *loader = NULL;
-  gnu::gcj::runtime::StackTrace *t 
-    = new gnu::gcj::runtime::StackTrace(4);
-  java::lang::Class *klass = NULL;
-  try
-    {
-      for (int i = 2; !klass; i++)
-	{
-	  klass = t->classAt (i);
-	}
-      loader = klass->getClassLoaderInternal();
-    }
-  catch (::java::lang::ArrayIndexOutOfBoundsException *e)
-    {
-      // FIXME: RuntimeError
-    }
-
-  return loader;
+  return obj;
 }
 
 java::lang::ClassLoader*
Index: java/io/natVMObjectStreamClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/natVMObjectStreamClass.cc,v
retrieving revision 1.1
diff -u -r1.1 natVMObjectStreamClass.cc
--- java/io/natVMObjectStreamClass.cc	20 Jan 2003 06:46:28 -0000	1.1
+++ java/io/natVMObjectStreamClass.cc	21 Feb 2005 20:48:10 -0000
@@ -13,11 +13,75 @@
 
 #include <java/io/VMObjectStreamClass.h>
 #include <java/lang/Class.h>
+#include <java/lang/reflect/Field.h>
+
+using namespace java::lang::reflect;
 
 jboolean
 java::io::VMObjectStreamClass::hasClassInitializer (jclass klass)
 {
+  if (klass->isPrimitive())
+    return false;
   _Jv_Method *meth = _Jv_GetMethodLocal(klass, gcj::clinit_name,
 					       gcj::void_signature);
   return (meth != NULL);
 }
+
+void
+java::io::VMObjectStreamClass::setDoubleNative (Field *f, jobject obj, 
+						jdouble val)
+{
+  f->setDouble (NULL, obj, val, false);
+}
+
+void 
+java::io::VMObjectStreamClass::setFloatNative (Field *f, jobject obj, 
+					       jfloat val)
+{
+  f->setFloat (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setLongNative (Field *f, jobject obj, jlong val)
+{
+  f->setLong (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setIntNative (Field *f, jobject obj, jint val)
+{
+  f->setInt (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setShortNative (Field *f, jobject obj, 
+					       jshort val)
+{
+  f->setShort (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setCharNative (Field *f, jobject obj, jchar val)
+{
+  f->setChar (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setByteNative (Field *f, jobject obj, jbyte val)
+{
+  f->setByte (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setBooleanNative (Field *f, jobject obj,
+						 jboolean val)
+{
+  f->setBoolean (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setObjectNative (Field *f, jobject obj, 
+						jobject val)
+{
+  f->set (NULL, obj, val, f->getType(), false);
+}
Index: java/lang/reflect/Field.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/Field.java,v
retrieving revision 1.9
diff -u -r1.9 Field.java
--- java/lang/reflect/Field.java	21 Jul 2003 01:54:06 -0000	1.9
+++ java/lang/reflect/Field.java	21 Feb 2005 20:48:10 -0000
@@ -23,6 +23,9 @@
   // Offset in bytes from the start of declaringClass's fields array.
   private int offset;
 
+  // The Class (or primitive TYPE) of this field.
+  private Class type;
+
   // This is instantiated by Class sometimes, but it uses C++ and
   // avoids the Java protection check.
   Field ()
@@ -136,76 +139,79 @@
   public void setByte (Object obj, byte b)
     throws IllegalArgumentException, IllegalAccessException
   {
-    setByte(null, obj, b);
+    setByte(null, obj, b, true);
   }
 
   public void setShort (Object obj,  short s)
     throws IllegalArgumentException, IllegalAccessException
   {
-    setShort(null, obj, s);
+    setShort(null, obj, s, true);
   }
 
   public void setInt (Object obj, int i)
     throws IllegalArgumentException, IllegalAccessException
   {
-    setInt(null, obj, i);
+    setInt(null, obj, i, true);
   }
 
   public void setLong (Object obj, long l)
     throws IllegalArgumentException, IllegalAccessException
   {
-    setLong(null, obj, l);
+    setLong(null, obj, l, true);
   }
 
   public void setFloat (Object obj, float f)
     throws IllegalArgumentException, IllegalAccessException
   {
-    setFloat(null, obj, f);
+    setFloat(null, obj, f, true);
   }
 
   public void setDouble (Object obj, double d)
     throws IllegalArgumentException, IllegalAccessException
   {
-    setDouble(null, obj, d);
+    setDouble(null, obj, d, true);
   }
 
   public void setChar (Object obj, char c)
     throws IllegalArgumentException, IllegalAccessException
   {
-    setChar(null, obj, c);
+    setChar(null, obj, c, true);
   }
 
   public void setBoolean (Object obj, boolean b)
     throws IllegalArgumentException, IllegalAccessException
   {
-    setBoolean(null, obj, b);
+    setBoolean(null, obj, b, true);
   }
 
-  private native void setByte (Class caller, Object obj, byte b)
+  native void setByte (Class caller, Object obj, byte b, boolean checkFinal)
     throws IllegalArgumentException, IllegalAccessException;
 
-  private native void setShort (Class caller, Object obj, short s)
+  native void setShort (Class caller, Object obj, short s, boolean checkFinal)
     throws IllegalArgumentException, IllegalAccessException;
 
-  private native void setInt (Class caller, Object obj, int i)
+  native void setInt (Class caller, Object obj, int i, boolean checkFinal)  
     throws IllegalArgumentException, IllegalAccessException;
 
-  private native void setLong (Class caller, Object obj, long l)
+  native void setLong (Class caller, Object obj, long l, boolean checkFinal)
     throws IllegalArgumentException, IllegalAccessException;
 
-  private native void setFloat (Class caller, Object obj, float f)
+  native void setFloat (Class caller, Object obj, float f, boolean checkFinal)
     throws IllegalArgumentException, IllegalAccessException;
 
-  private native void setDouble (Class caller, Object obj, double d)
+  native void setDouble (Class caller, Object obj, double d,
+			 boolean checkFinal)
     throws IllegalArgumentException, IllegalAccessException;
 
-  private native void setChar (Class caller, Object obj, char c)
+  native void setChar (Class caller, Object obj, char c, boolean checkFinal)
     throws IllegalArgumentException, IllegalAccessException;
 
-  private native void setBoolean (Class caller, Object obj, boolean b)
+  native void setBoolean (Class caller, Object obj, boolean b,
+			  boolean checkFinal)
     throws IllegalArgumentException, IllegalAccessException;
 
-  private native void set (Class caller, Object obj, Object val, Class type)
+  native void set (Class caller, Object obj, Object val, Class type, 
+		   boolean checkFinal)
     throws IllegalArgumentException, IllegalAccessException;
 
   public void set (Object object, Object value)
@@ -219,23 +225,23 @@
   {
     Class type = getType();
     if (! type.isPrimitive())
-      set(caller, object, value, type);
+      set(caller, object, value, type, true);
     else if (value instanceof Byte)
-      setByte(caller, object, ((Byte) value).byteValue());
+      setByte(caller, object, ((Byte) value).byteValue(), true);
     else if (value instanceof Short)
-      setShort (caller, object, ((Short) value).shortValue());
+      setShort (caller, object, ((Short) value).shortValue(), true);
     else if (value instanceof Integer)
-      setInt(caller, object, ((Integer) value).intValue());
+      setInt(caller, object, ((Integer) value).intValue(), true);
     else if (value instanceof Long)
-      setLong(caller, object, ((Long) value).longValue());
+      setLong(caller, object, ((Long) value).longValue(), true);
     else if (value instanceof Float)
-      setFloat(caller, object, ((Float) value).floatValue());
+      setFloat(caller, object, ((Float) value).floatValue(), true);
     else if (value instanceof Double)
-      setDouble(caller, object, ((Double) value).doubleValue());
+      setDouble(caller, object, ((Double) value).doubleValue(), true);
     else if (value instanceof Character)
-      setChar(caller, object, ((Character) value).charValue());
+      setChar(caller, object, ((Character) value).charValue(), true);
     else if (value instanceof Boolean)
-      setBoolean(caller, object, ((Boolean) value).booleanValue());
+      setBoolean(caller, object, ((Boolean) value).booleanValue(), true);
     else
       throw new IllegalArgumentException();
   }
Index: java/lang/reflect/natField.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/natField.cc,v
retrieving revision 1.16
diff -u -r1.16 natField.cc
--- java/lang/reflect/natField.cc	25 Nov 2004 03:47:05 -0000	1.16
+++ java/lang/reflect/natField.cc	21 Feb 2005 20:48:10 -0000
@@ -45,14 +45,19 @@
 jclass
 java::lang::reflect::Field::getType ()
 {
-  jfieldID fld = _Jv_FromReflectedField (this);
-  JvSynchronize sync (declaringClass);
-  _Jv_Linker::resolve_field (fld, declaringClass->getClassLoaderInternal ());
-  return fld->type;
+  if (type == NULL)
+    {
+      jfieldID fld = _Jv_FromReflectedField (this);
+      JvSynchronize sync (declaringClass);
+      _Jv_Linker::resolve_field (fld, declaringClass->getClassLoaderInternal ());
+      type = fld->type;
+    }
+  return type;
 }
 
 static void*
-getAddr (java::lang::reflect::Field* field, jclass caller, jobject obj)
+getAddr (java::lang::reflect::Field* field, jclass caller, jobject obj,
+         jboolean checkFinal)
 {
   // FIXME: we know CALLER is NULL here.  At one point we planned to
   // have the compiler insert the caller as a hidden argument in some
@@ -63,6 +68,12 @@
   
   jfieldID fld = _Jv_FromReflectedField (field);
   _Jv_ushort flags = fld->getModifiers();
+
+  // Setting a final field is usually not allowed.
+  if (checkFinal
+      && field->getModifiers() & java::lang::reflect::Modifier::FINAL)
+    throw new java::lang::IllegalAccessException(JvNewStringUTF 
+      ("Field is final"));
   
   // Check accessibility, if required.
   if (! (Modifier::isPublic (flags) || field->isAccessible()))
@@ -180,56 +191,56 @@
 jboolean
 java::lang::reflect::Field::getBoolean (jclass caller, jobject obj)
 {
-  return ::getBoolean (this->getType(), getAddr (this, caller, obj));
+  return ::getBoolean (this->getType(), getAddr (this, caller, obj, false));
 }
 
 jchar
 java::lang::reflect::Field::getChar (jclass caller, jobject obj)
 {
-  return ::getChar (this->getType(), getAddr (this, caller, obj));
+  return ::getChar (this->getType(), getAddr (this, caller, obj, false));
 }
 
 jbyte
 java::lang::reflect::Field::getByte (jclass caller, jobject obj)
 {
-  return ::getByte (this->getType(), getAddr (this, caller, obj));
+  return ::getByte (this->getType(), getAddr (this, caller, obj, false));
 }
 
 jshort
 java::lang::reflect::Field::getShort (jclass caller, jobject obj)
 {
-  return ::getShort (this->getType(), getAddr (this, caller, obj));
+  return ::getShort (this->getType(), getAddr (this, caller, obj, false));
 }
 
 jint
 java::lang::reflect::Field::getInt (jclass caller, jobject obj)
 {
-  return ::getInt (this->getType(), getAddr (this, caller, obj));
+  return ::getInt (this->getType(), getAddr (this, caller, obj, false));
 }
 
 jlong
 java::lang::reflect::Field::getLong (jclass caller, jobject obj)
 {
-  return ::getLong (this->getType(), getAddr (this, caller, obj));
+  return ::getLong (this->getType(), getAddr (this, caller, obj, false));
 }
 
 jfloat
 java::lang::reflect::Field::getFloat (jclass caller, jobject obj)
 {
-  return ::getFloat (this->getType(), getAddr (this, caller, obj));
+  return ::getFloat (this->getType(), getAddr (this, caller, obj, false));
 }
 
 jdouble
 java::lang::reflect::Field::getDouble (jclass caller, jobject obj)
 {
-  return ::getDouble (this->getType(), getAddr (this, caller, obj));
+  return ::getDouble (this->getType(), getAddr (this, caller, obj, false));
 }
 
 jobject
 java::lang::reflect::Field::get (jclass caller, jobject obj)
 {
   jclass type = this->getType();
-  void* addr = getAddr (this, caller, obj);
+  void* addr = getAddr (this, caller, obj, false);
   if (! type->isPrimitive ())
     return * (jobject*) addr;
   if (type == JvPrimClass (double))
@@ -257,16 +268,6 @@
   throw new java::lang::IllegalArgumentException;
 }
 
-static void*
-setAddr (java::lang::reflect::Field* field, jclass caller, jobject obj)
-{
-  void *addr = getAddr(field, caller, obj);
-  if  (!field->isAccessible()
-	&& field->getModifiers() & java::lang::reflect::Modifier::FINAL)
-    throw new java::lang::IllegalAccessException();
-  return addr;
-}
-
 static void
 setBoolean (jclass type, void *addr, jboolean value)
 {
@@ -378,57 +379,66 @@
 }
 
 void
-java::lang::reflect::Field::setBoolean (jclass caller, jobject obj, jboolean b)
+java::lang::reflect::Field::setBoolean (jclass caller, jobject obj, jboolean b,
+					jboolean checkFinal)
 {
-  ::setBoolean (this->getType(), setAddr (this, caller, obj), b);
+  ::setBoolean (this->getType(), getAddr (this, caller, obj, checkFinal), b);
 }
 
 void
-java::lang::reflect::Field::setChar (jclass caller, jobject obj, jchar c)
+java::lang::reflect::Field::setChar (jclass caller, jobject obj, jchar c,
+				     jboolean checkFinal)
 {
-  ::setChar (this->getType(), setAddr (this, caller, obj), c);
+  ::setChar (this->getType(), getAddr (this, caller, obj, checkFinal), c);
 }
 
 void
-java::lang::reflect::Field::setByte (jclass caller, jobject obj, jbyte b)
+java::lang::reflect::Field::setByte (jclass caller, jobject obj, jbyte b,
+				     jboolean checkFinal)
 {
-  ::setByte (this->getType(), setAddr (this, caller, obj), b);
+  ::setByte (this->getType(), getAddr (this, caller, obj, checkFinal), b);
 }
 
 void
-java::lang::reflect::Field::setShort (jclass caller, jobject obj, jshort s)
+java::lang::reflect::Field::setShort (jclass caller, jobject obj, jshort s,
+				      jboolean checkFinal)
 {
-  ::setShort (this->getType(), setAddr (this, caller, obj), s);
+  ::setShort (this->getType(), getAddr (this, caller, obj, checkFinal), s);
 }
 
 void
-java::lang::reflect::Field::setInt (jclass caller, jobject obj, jint i)
+java::lang::reflect::Field::setInt (jclass caller, jobject obj, jint i,
+				    jboolean checkFinal)
 {
-  ::setInt (this->getType(), setAddr (this, caller, obj), i);
+  ::setInt (this->getType(), getAddr (this, caller, obj, checkFinal), i);
 }
 
 void
-java::lang::reflect::Field::setLong (jclass caller, jobject obj, jlong l)
+java::lang::reflect::Field::setLong (jclass caller, jobject obj, jlong l,
+				     jboolean checkFinal)
 {
-  ::setLong (this->getType(), setAddr (this, caller, obj), l);
+  ::setLong (this->getType(), getAddr (this, caller, obj, checkFinal), l);
 }
+
 void
-java::lang::reflect::Field::setFloat (jclass caller, jobject obj, jfloat f)
+java::lang::reflect::Field::setFloat (jclass caller, jobject obj, jfloat f,
+				      jboolean checkFinal)
 {
-  ::setFloat (this->getType(), setAddr (this, caller, obj), f);
+  ::setFloat (this->getType(), getAddr (this, caller, obj, checkFinal), f);
 }
 
 void
-java::lang::reflect::Field::setDouble (jclass caller, jobject obj, jdouble d)
+java::lang::reflect::Field::setDouble (jclass caller, jobject obj, jdouble d,
+				       jboolean checkFinal)
 {
-  ::setDouble (this->getType(), setAddr (this, caller, obj), d);
+  ::setDouble (this->getType(), getAddr (this, caller, obj, checkFinal), d);
 }
 
 void
 java::lang::reflect::Field::set (jclass caller, jobject object, jobject value,
-				 jclass type)
+				 jclass type, jboolean checkFinal)
 {
-  void* addr = setAddr (this, caller, object);
+  void* addr = getAddr (this, caller, object, checkFinal);
   if (value != NULL && ! _Jv_IsInstanceOf (value, type))
     throw new java::lang::IllegalArgumentException;
   * (jobject*) addr = value;

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