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]

Classpath ObjectIn/OutputStream merge


Hi,

Here is finally the remaining ObjectIn/OutputStream remerge with GNU
Classpath. It is still not 100% complete but I think this is important
enough to get into 3.3. The old code could get into infinite recursion
some of the time (triggered by some Mauve tests, which was why they were
disabled). The things that have to happen for a full merge are:

- Reindent both Classpath and libgcj code (will do this as soon as this
goes in.
- Merge getCurrentClassLoader() code. libgcj just always returns the
system classloader for now.
- ObjectInputStream DataInput primitive wrappers. I just don't
understand the Classpath code. But it does not impact the Mauve tests
and the libgcj code didn't do it in the past anyway.

Even without this the patch is already large but all important logic is
in. I tried to make a detailed ChangeLog (note that the diff looks huge
but if requested I can send a diff -w that shows that a big part of the
patch is just reindenting two large try-catch-finally blocks):

2003-02-23  Mark Wielaard  <mark at klomp dot org>

	* Makefile.am (nat_source_files): Remove
	java/io/natObjectOutputStream.cc.
	* Makefile.in: Regenerated.
	* mauve-libgcj: Don't exclude java.io.ObjectInputOutput tests.
	* java/io/ObjectStreamField.java (typename): New field.
	(ObjectStreamField(String, Class)): Initialize new field.
	(ObjectStreamField(String, String)): New Constructor.
	(getTypeCode): Use new field.
	(getTypeString): Use new field.
	* java/io/ObjectOutputStream.java (writeObject): Rethrow fatal
	ObjectStreamExceptions. Remember and reset old BlockDataMode.
	Handle reading of Proxy classes. Never drain(),	just write
	TC_ENDBLOCKDATA. Rethrow ObjectStreamExceptions.
	(drain): Check writeDataAsBlocks before calling writeBlockDataHeader.
	(flush): Call flush(), not just drain().
	(writeBoolean): Always use blockDataOutput.
	(writeByte): Likewise.
	(writeShort): Likewise.
	(writeChar): Likewise.
	(writeInt): Likewise.
	(writeLong): Likewise.
	(writeFloat): Likewise.
	(writeDouble): Likewise.
	(writeBytes): Likewise.
	(putfield (put(String,Object))): Throw IllegalArgumentException if
	field cannot be found.
	(putfield (write(ObjectOutput))): Remember old BlockDataMode.
	(writeArraySizeAndElements): Write byte[] in one go.
	(writeFields): Write TC_ENDBLOCKDATA when call_write_method, otherwise
	set BlockDataMode to false.
	(annotateProxyClass): New method.	
	(defaultProtocolVersion): Now defaults to PROTOCOL_VERSION_2
	(getField): No longer native.
	(getMethod): Likewise.
	(setBlockDataMode): Always drain() on switch, return old mode.
	(static): New static code block.
	* java/io/natObjectOutputStream.cc: Removed.
	* java/io/ObjectInputStream.java (getField): No longer native.
	(getMethod): Likewise.
	(readObject): Remember and reset old BlockDataMode. Track whether
	object is consumed. Handle TC_ENDBLOCKDATA, TC_PROXYCLASSDESC and
	TC_LONGSTRING.
	(defaultReadObject): Set BlockDataMode to false during readFields.
	(resolveClass): Create new SecurityManager if necessary.
	Use Class.forName() if null ClassLoader found.
	(read(byte[],int,int): Copy remaining bytes to data before calling
	readNextBlock().
	(readFields): Set and reset BlockDataMode on call_read_method.
	Catch NoSuchFieldErrors.
	(setBlockDataMode): Return old mode.
	(static): New static code block.
	* java/io/natObjectInputStream.cc (getField): Removed.
	(getMethod): Likewise.

OK for branch and mainline?

It enables the Mauve tests that we were unable to run previously. This
does introduce some new failures (but also 35 new passes):

FAIL: gnu.testlet.java.io.ObjectInputOutput.InputTest: gnu.testlet.java.io.ObjectInputOutput.Test$GetPutField (number 1)
FAIL: gnu.testlet.java.io.ObjectInputOutput.OutputTest: Serializable: gnu.testlet.java.io.ObjectInputOutput.Test$Extern () (number 2)
FAIL: gnu.testlet.java.io.ObjectInputOutput.OutputTest: Serializable: test(str=null, x=0) (number 2)
FAIL: gnu.testlet.java.io.ObjectInputOutput.SerTest (number 2)

These failures are the same as seen with Kissme+Classpath and the old
libgcj code could either not run these tests in the first place or gave
the same results. There is a Classpath patch pending to resolve the last
one. I will try to investigate the others next week and either fix them
or xfail them.

Cheers,

Mark
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.279
diff -u -r1.279 Makefile.am
--- Makefile.am	18 Feb 2003 07:26:20 -0000	1.279
+++ Makefile.am	23 Feb 2003 15:55:32 -0000
@@ -2496,7 +2496,6 @@
 java/io/natFile.cc \
 java/io/natFileDescriptor.cc \
 java/io/natObjectInputStream.cc \
-java/io/natObjectOutputStream.cc \
 java/io/natVMObjectStreamClass.cc \
 java/lang/natCharacter.cc \
 java/lang/natClass.cc \
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.in,v
retrieving revision 1.300
diff -u -r1.300 Makefile.in
--- Makefile.in	18 Feb 2003 07:26:20 -0000	1.300
+++ Makefile.in	23 Feb 2003 15:55:37 -0000
@@ -65,6 +65,7 @@
 target_triplet = @target@
 AR = @AR@
 AS = @AS@
+BACKTRACESPEC = @BACKTRACESPEC@
 CC = @CC@
 CHECKREFSPEC = @CHECKREFSPEC@
 COMPPATH = @COMPPATH@
@@ -91,6 +92,7 @@
 GTK_CONFIG = @GTK_CONFIG@
 GTK_LIBS = @GTK_LIBS@
 HASH_SYNC_SPEC = @HASH_SYNC_SPEC@
+IEEESPEC = @IEEESPEC@
 INCLTDL = @INCLTDL@
 INTERPRETER = @INTERPRETER@
 JC1GCSPEC = @JC1GCSPEC@
@@ -2255,7 +2257,6 @@
 java/io/natFile.cc \
 java/io/natFileDescriptor.cc \
 java/io/natObjectInputStream.cc \
-java/io/natObjectOutputStream.cc \
 java/io/natVMObjectStreamClass.cc \
 java/lang/natCharacter.cc \
 java/lang/natClass.cc \
@@ -2425,18 +2426,16 @@
 gnu/gcj/runtime/natStackTrace.lo gnu/gcj/runtime/natStringBuffer.lo \
 gnu/gcj/runtime/natVMClassLoader.lo gnu/java/nio/natByteBufferImpl.lo \
 gnu/java/nio/natCharBufferImpl.lo gnu/java/nio/natDoubleBufferImpl.lo \
-gnu/java/nio/natFileChannelImpl.lo \
-gnu/java/nio/natFloatBufferImpl.lo gnu/java/nio/natIntBufferImpl.lo \
-gnu/java/nio/natLongBufferImpl.lo \
-gnu/java/nio/natSelectorImpl.lo \
-gnu/java/nio/natShortBufferImpl.lo gnu/java/nio/natSocketChannelImpl.lo \
-java/io/natFile.lo java/io/natFileDescriptor.lo \
-java/io/natObjectInputStream.lo \
-java/io/natObjectOutputStream.lo java/io/natVMObjectStreamClass.lo \
-java/lang/natCharacter.lo java/lang/natClass.lo \
-java/lang/natClassLoader.lo java/lang/natConcreteProcess.lo \
-java/lang/natDouble.lo java/lang/natFloat.lo java/lang/natMath.lo \
-java/lang/natObject.lo java/lang/natRuntime.lo java/lang/natString.lo \
+gnu/java/nio/natFileChannelImpl.lo gnu/java/nio/natFloatBufferImpl.lo \
+gnu/java/nio/natIntBufferImpl.lo gnu/java/nio/natLongBufferImpl.lo \
+gnu/java/nio/natSelectorImpl.lo gnu/java/nio/natShortBufferImpl.lo \
+gnu/java/nio/natSocketChannelImpl.lo java/io/natFile.lo \
+java/io/natFileDescriptor.lo java/io/natObjectInputStream.lo \
+java/io/natVMObjectStreamClass.lo java/lang/natCharacter.lo \
+java/lang/natClass.lo java/lang/natClassLoader.lo \
+java/lang/natConcreteProcess.lo java/lang/natDouble.lo \
+java/lang/natFloat.lo java/lang/natMath.lo java/lang/natObject.lo \
+java/lang/natRuntime.lo java/lang/natString.lo \
 java/lang/natStringBuffer.lo java/lang/natSystem.lo \
 java/lang/natThread.lo java/lang/natVMSecurityManager.lo \
 java/lang/ref/natReference.lo java/lang/reflect/natArray.lo \
@@ -2599,7 +2598,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = gtar
+TAR = tar
 GZIP_ENV = --best
 DIST_SUBDIRS =  @DIRLTDL@ testsuite gcj include @DIRLTDL@ gcj include
 DEP_FILES =  .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
@@ -3270,7 +3269,6 @@
 .deps/java/io/WriteAbortedException.P .deps/java/io/Writer.P \
 .deps/java/io/natFile.P .deps/java/io/natFileDescriptor.P \
 .deps/java/io/natObjectInputStream.P \
-.deps/java/io/natObjectOutputStream.P \
 .deps/java/io/natVMObjectStreamClass.P \
 .deps/java/lang/AbstractMethodError.P \
 .deps/java/lang/ArithmeticException.P \
Index: mauve-libgcj
===================================================================
RCS file: /cvs/gcc/gcc/libjava/mauve-libgcj,v
retrieving revision 1.25
diff -u -r1.25 mauve-libgcj
--- mauve-libgcj	13 Oct 2002 11:10:27 -0000	1.25
+++ mauve-libgcj	23 Feb 2003 15:55:37 -0000
@@ -15,7 +15,6 @@
 
 # The following tests seem to hang or crash the testsuite.
 # This a problem when running Mauve "standalone".
-!java.io.ObjectInputOutput
 !java.lang.reflect.Array.newInstance
 
 # Character.unicode seems to be very broken (the test)
Index: java/io/ObjectInputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectInputStream.java,v
retrieving revision 1.13
diff -u -r1.13 ObjectInputStream.java
--- java/io/ObjectInputStream.java	1 Oct 2002 03:46:42 -0000	1.13
+++ java/io/ObjectInputStream.java	23 Feb 2003 15:55:38 -0000
@@ -1,5 +1,5 @@
 /* ObjectInputStream.java -- Class used to read serialized objects
-   Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -38,8 +38,6 @@
 
 package java.io;
 
-import gnu.classpath.Configuration;
-
 import java.lang.reflect.Array;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
@@ -53,7 +51,7 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationTargetException;
 
-
+import gnu.classpath.Configuration;
 
 public class ObjectInputStream extends InputStream
   implements ObjectInput, ObjectStreamConstants
@@ -130,286 +128,343 @@
     Object ret_val;
     was_deserializing = this.isDeserializing;
 
-    if (! was_deserializing)
-      setBlockDataMode (false);
+    boolean is_consumed = false;
+    boolean old_mode = setBlockDataMode (false);
 
     this.isDeserializing = true;
 
     byte marker = this.realInputStream.readByte ();
     dumpElement ("MARKER: 0x" + Integer.toHexString(marker) + " ");
 
-    switch (marker)
-    {
-      case TC_BLOCKDATA:
-      case TC_BLOCKDATALONG:
-	if (marker == TC_BLOCKDATALONG) 
-	  dumpElementln ("BLOCKDATALONG");
-	else
-	  dumpElementln ("BLOCKDATA");
-	readNextBlock (marker);
-	throw new StreamCorruptedException ("Unexpected blockData");
-
-      case TC_NULL:
-	dumpElementln ("NULL");
-	ret_val = null;
-	break;
-
-      case TC_REFERENCE:
-      {
-	dumpElement ("REFERENCE ");
-	Integer oid = new Integer (this.realInputStream.readInt ());
-	dumpElementln (Integer.toHexString(oid.intValue()));
-	ret_val = ((ObjectIdentityWrapper)
-		   this.objectLookupTable.get (oid)).object;
-	break;
-      }
-
-      case TC_CLASS:
-      {
-	dumpElementln ("CLASS");
-	ObjectStreamClass osc = (ObjectStreamClass)readObject ();
-	Class clazz = osc.forClass ();
-	assignNewHandle (clazz);
-	ret_val = clazz;
-	break;
-      }
-
-      case TC_CLASSDESC:
-      {
-	dumpElement ("CLASSDESC NAME=");
-	String name = this.realInputStream.readUTF ();
-	dumpElement (name + "; UID=");
-	long uid = this.realInputStream.readLong ();
-	dumpElement (Long.toHexString(uid) + "; FLAGS=");
-	byte flags = this.realInputStream.readByte ();
-	dumpElement (Integer.toHexString(flags) + "; FIELD COUNT=");
-	short field_count = this.realInputStream.readShort ();
-	dumpElementln (Short.toString(field_count));
-	ObjectStreamField[] fields = new ObjectStreamField[field_count];
-
-	ObjectStreamClass osc = new ObjectStreamClass (name, uid,
-						       flags, fields);
-	assignNewHandle (osc);
-
-	for (int i=0; i < field_count; i++)
-	{
-	  dumpElement ("  TYPE CODE=");
-	  char type_code = (char)this.realInputStream.readByte ();
-	  dumpElement (type_code + "; FIELD NAME=");
-	  String field_name = this.realInputStream.readUTF ();
-	  dumpElementln (field_name);
-	  String class_name;
-
-	  if (type_code == 'L' || type_code == '[')
-	    class_name = (String)readObject ();
-	  else
-	    class_name = String.valueOf (type_code);
-
-	  fields[i] =
-	    new ObjectStreamField (field_name,
-				   TypeSignature.getClassForEncoding
-				   (class_name));
-	}
-
-	Class cl = resolveClass (osc);
-	osc.setClass (cl);
-	setBlockDataMode (false);
-
-	if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
-	  throw new IOException ("Data annotated to class was not consumed.");
-	dumpElementln ("ENDBLOCKDATA ");
-
-	osc.setSuperclass ((ObjectStreamClass)readObject ());
-	ret_val = osc;
-	break;
-      }
-
-      case TC_STRING:
-      {
-	dumpElement ("STRING=");
-	String s = this.realInputStream.readUTF ();
-	dumpElementln (s);
-	ret_val = processResolution (s, assignNewHandle (s));
-	break;
-      }
-
-      case TC_ARRAY:
-      {
-	dumpElementln ("ARRAY");
-	ObjectStreamClass osc = (ObjectStreamClass)readObject ();
-	Class componentType = osc.forClass ().getComponentType ();
-	dumpElement ("ARRAY LENGTH=");
-	int length = this.realInputStream.readInt ();
-	dumpElementln (length + "; COMPONENT TYPE=" + componentType);
-	Object array = Array.newInstance (componentType, length);
-	int handle = assignNewHandle (array);
-	readArrayElements (array, componentType);
-	for (int i=0, len=Array.getLength(array); i < len; i++)
-	  dumpElementln ("  ELEMENT[" + i + "]=" + Array.get(array, i));
-	ret_val = processResolution (array, handle);
-	break;
-      }
-
-      case TC_OBJECT:
+    try
       {
-	dumpElementln ("OBJECT");
-	ObjectStreamClass osc = (ObjectStreamClass)readObject ();
-	Class clazz = osc.forClass ();
-
-	if (!Serializable.class.isAssignableFrom (clazz))
-	  throw new NotSerializableException (clazz + " is not Serializable, and thus cannot be deserialized.");
-
-	if (Externalizable.class.isAssignableFrom (clazz))
-	{
-	  Externalizable obj = null;
-
-	  try
-	  {
-	    obj = (Externalizable)clazz.newInstance ();
-	  }
-	  catch (InstantiationException e)
-	  {
-	    throw new ClassNotFoundException ("Instance of " + clazz
-					      + " could not be created");
-	  }
-	  catch (IllegalAccessException e)
-	  {
-	    throw new ClassNotFoundException ("Instance of " + clazz
-					      + " could not be created because class or zero-argument constructor is not accessible");
-	  }
-	  catch (NoSuchMethodError e)
-	  {
-	    throw new ClassNotFoundException ("Instance of " + clazz
-					      + " could not be created because zero-argument constructor is not defined");
-	  }
-
-	  int handle = assignNewHandle (obj);
-
-	  boolean read_from_blocks = ((osc.getFlags () & SC_BLOCK_DATA) != 0);
-
-	  if (read_from_blocks)
-	    setBlockDataMode (true);
-
-	  obj.readExternal (this);
-
-	  if (read_from_blocks)
-	    setBlockDataMode (false);
-
-	  ret_val = processResolution (obj, handle);
-	  break;
-	} // end if (Externalizable.class.isAssignableFrom (clazz))
-
-	// 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 ()))
-	  first_nonserial = first_nonserial.getSuperclass ();
-
-//	DEBUGln ("Using " + first_nonserial
-//		 + " as starting point for constructing " + clazz);
-
-	Object obj = null;
-	obj = newObject (clazz, first_nonserial);
-
-	if (obj == null)
-	  throw new ClassNotFoundException ("Instance of " + clazz +
-					    " could not be created");
-
-	int handle = assignNewHandle (obj);
-	this.currentObject = obj;
-	ObjectStreamClass[] hierarchy =
-	  ObjectStreamClass.getObjectStreamClasses (clazz);
-
-//	DEBUGln ("Got class hierarchy of depth " + hierarchy.length);
-
-	boolean has_read;
-	for (int i=0; i < hierarchy.length; i++)
-	{
-	  this.currentObjectStreamClass = hierarchy[i];
-
-	  dumpElementln ("Reading fields of "
-		   + this.currentObjectStreamClass.getName ());
-
-	  has_read = true;
-
-	  try
-	  {
-	    this.currentObjectStreamClass.forClass ().
-	      getDeclaredMethod ("readObject", readObjectParams);
-	  }
-	  catch (NoSuchMethodException e)
+	switch (marker)
 	  {
-	    has_read = false;
-	  }
+	  case TC_ENDBLOCKDATA:
+	    {
+	      ret_val = null;
+	      is_consumed = true;
+	      break;
+	    }
+	    
+	  case TC_BLOCKDATA:
+	  case TC_BLOCKDATALONG:
+	    {
+	      if (marker == TC_BLOCKDATALONG) 
+		dumpElementln ("BLOCKDATALONG");
+	      else
+		dumpElementln ("BLOCKDATA");
+	      readNextBlock (marker);
+	      throw new StreamCorruptedException ("Unexpected blockData");
+	    }
+
+	  case TC_NULL:
+	    {
+	      dumpElementln ("NULL");
+	      ret_val = null;
+	      break;
+	    }
+	    
+	  case TC_REFERENCE:
+	    {
+	      dumpElement ("REFERENCE ");
+	      Integer oid = new Integer (this.realInputStream.readInt ());
+	      dumpElementln (Integer.toHexString(oid.intValue()));
+	      ret_val = ((ObjectIdentityWrapper)
+			 this.objectLookupTable.get (oid)).object;
+	      break;
+	    }
+	    
+	  case TC_CLASS:
+	    {
+	      dumpElementln ("CLASS");
+	      ObjectStreamClass osc = (ObjectStreamClass)readObject ();
+	      Class clazz = osc.forClass ();
+	      assignNewHandle (clazz);
+	      ret_val = clazz;
+	      break;
+	    }
+
+	  case TC_PROXYCLASSDESC:
+	    {
+	      dumpElementln ("PROXYCLASS");
+	      int n_intf = this.realInputStream.readInt();
+	      String[] intfs = new String[n_intf];
+	      for (int i = 0; i < n_intf; i++)
+		{
+		  intfs[i] = this.realInputStream.readUTF();
+		  System.out.println(intfs[i]);
+		}
+	      
+	      boolean oldmode = setBlockDataMode (true);
+	      Class cl = resolveProxyClass(intfs);
+	      setBlockDataMode(oldmode);
+	      
+	      ObjectStreamClass osc = ObjectStreamClass.lookup(cl);
+	      assignNewHandle (osc);
+	      
+	      if (!is_consumed)
+		{
+		  byte b = this.realInputStream.readByte ();
+		  if (b != TC_ENDBLOCKDATA)
+		    throw new IOException ("Data annotated to class was not consumed." + b);
+		}
+	      else
+		is_consumed = false;
+	      ObjectStreamClass superosc = (ObjectStreamClass)readObject ();
+	      osc.setSuperclass (superosc);
+	      ret_val = osc;
+	      break;
+	    }
+
+	  case TC_CLASSDESC:
+	    {
+	      dumpElement ("CLASSDESC NAME=");
+	      String name = this.realInputStream.readUTF ();
+	      dumpElement (name + "; UID=");
+	      long uid = this.realInputStream.readLong ();
+	      dumpElement (Long.toHexString(uid) + "; FLAGS=");
+	      byte flags = this.realInputStream.readByte ();
+	      dumpElement (Integer.toHexString(flags) + "; FIELD COUNT=");
+	      short field_count = this.realInputStream.readShort ();
+	      dumpElementln (Short.toString(field_count));
+	      ObjectStreamField[] fields = new ObjectStreamField[field_count];
+	      
+	      ObjectStreamClass osc = new ObjectStreamClass (name, uid,
+							     flags, fields);
+	      assignNewHandle (osc);
+	      
+	      for (int i=0; i < field_count; i++)
+		{
+		  dumpElement ("  TYPE CODE=");
+		  char type_code = (char)this.realInputStream.readByte ();
+		  dumpElement (type_code + "; FIELD NAME=");
+		  String field_name = this.realInputStream.readUTF ();
+		  dumpElementln (field_name);
+		  String class_name;
+		  
+		  if (type_code == 'L' || type_code == '[')
+		    class_name = (String)readObject ();
+		  else
+		    class_name = String.valueOf (type_code);
+		  
+		  // There're many cases you can't get java.lang.Class from
+		  // typename if your context class loader can't load it,
+		  // then use typename to construct the field
+		  fields[i] =
+		    new ObjectStreamField (field_name, class_name);
+		}
+	      
+	      boolean oldmode = setBlockDataMode (true);
+	      osc.setClass (resolveClass (osc));
+	      setBlockDataMode (oldmode);
+	      
+	      if (!is_consumed)
+		{
+		  byte b = this.realInputStream.readByte ();
+		  if (b != TC_ENDBLOCKDATA)
+		    throw new IOException ("Data annotated to class was not consumed." + b);
+		}
+	      else
+		is_consumed = false;
+	      
+	      osc.setSuperclass ((ObjectStreamClass)readObject ());
+	      ret_val = osc;
+	      break;
+	    }
+	    
+	  case TC_STRING:
+	  case TC_LONGSTRING:
+	    {
+	      dumpElement ("STRING=");
+	      String s = this.realInputStream.readUTF ();
+	      dumpElementln (s);
+	      ret_val = processResolution (s, assignNewHandle (s));
+	      break;
+	    }
+
+	  case TC_ARRAY:
+	    {
+	      dumpElementln ("ARRAY");
+	      ObjectStreamClass osc = (ObjectStreamClass)readObject ();
+	      Class componentType = osc.forClass ().getComponentType ();
+	      dumpElement ("ARRAY LENGTH=");
+	      int length = this.realInputStream.readInt ();
+	      dumpElementln (length + "; COMPONENT TYPE=" + componentType);
+	      Object array = Array.newInstance (componentType, length);
+	      int handle = assignNewHandle (array);
+	      readArrayElements (array, componentType);
+	      for (int i=0, len=Array.getLength(array); i < len; i++)
+		dumpElementln ("  ELEMENT[" + i + "]=" + Array.get(array, i));
+	      ret_val = processResolution (array, handle);
+	      break;
+	    }
+
+	  case TC_OBJECT:
+	    {
+	      dumpElementln ("OBJECT");
+	      ObjectStreamClass osc = (ObjectStreamClass)readObject ();
+	      Class clazz = osc.forClass ();
+	      
+	      if (!Serializable.class.isAssignableFrom (clazz))
+		throw new NotSerializableException (clazz + " is not Serializable, and thus cannot be deserialized.");
+	      
+	      if (Externalizable.class.isAssignableFrom (clazz))
+		{
+		  Externalizable obj = null;
+		  
+		  try
+		    {
+		      obj = (Externalizable)clazz.newInstance ();
+		    }
+		  catch (InstantiationException e)
+		    {
+		      throw new ClassNotFoundException ("Instance of " + clazz
+							+ " could not be created");
+		    }
+		  catch (IllegalAccessException e)
+		    {
+		      throw new ClassNotFoundException ("Instance of " + clazz
+							+ " could not be created because class or zero-argument constructor is not accessible");
+		    }
+		  catch (NoSuchMethodError e)
+		    {
+		      throw new ClassNotFoundException ("Instance of " + clazz
+							+ " could not be created because zero-argument constructor is not defined");
+		    }
+		  
+		  int handle = assignNewHandle (obj);
+		  
+		  boolean read_from_blocks = ((osc.getFlags () & SC_BLOCK_DATA) != 0);
+		  
+		  boolean oldmode = this.readDataFromBlock;
+		  if (read_from_blocks)
+		    setBlockDataMode (true);
+		  
+		  obj.readExternal (this);
+		  
+		  if (read_from_blocks)
+		    setBlockDataMode (oldmode);
+		  
+		  ret_val = processResolution (obj, handle);
+		  break;
+		} // end if (Externalizable.class.isAssignableFrom (clazz))
+	      
+	      // 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 ()))
+		first_nonserial = first_nonserial.getSuperclass ();
+	      
+	      //	DEBUGln ("Using " + first_nonserial
+	      //		 + " as starting point for constructing " + clazz);
+	      
+	      Object obj = null;
+	      obj = newObject (clazz, first_nonserial);
+	      
+	      if (obj == null)
+		throw new ClassNotFoundException ("Instance of " + clazz +
+						  " could not be created");
+	      
+	      int handle = assignNewHandle (obj);
+	      this.currentObject = obj;
+	      ObjectStreamClass[] hierarchy =
+		ObjectStreamClass.getObjectStreamClasses (clazz);
+	      
+	      //	DEBUGln ("Got class hierarchy of depth " + hierarchy.length);
+	      
+	      boolean has_read;
+	      for (int i=0; i < hierarchy.length; i++)
+		{
+		  this.currentObjectStreamClass = hierarchy[i];
+		  
+		  dumpElementln ("Reading fields of "
+				 + this.currentObjectStreamClass.getName ());
+		  
+		  has_read = true;
+		  
+		  try
+		    {
+		      this.currentObjectStreamClass.forClass ().
+			getDeclaredMethod ("readObject", readObjectParams);
+		    }
+		  catch (NoSuchMethodException e)
+		    {
+		      has_read = false;
+		    }
+
+		  // XXX: should initialize fields in classes in the hierarchy
+		  // that aren't in the stream
+		  // should skip over classes in the stream that aren't in the
+		  // real classes hierarchy
+		  readFields (obj, this.currentObjectStreamClass.fields,
+			      has_read, this.currentObjectStreamClass);
+
+		  if (has_read)
+		    {
+		      dumpElement ("ENDBLOCKDATA? ");
+		      try
+			{
+			  // FIXME: XXX: This try block is to catch EOF which is
+			  // thrown for some objects.  That indicates a bug in the logic.
+			  if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
+			    throw new IOException ("No end of block data seen for class with readObject (ObjectInputStream) method.");
+			  dumpElementln ("yes");
+			}
+		      catch (EOFException e)
+			{
+			  dumpElementln ("no, got EOFException");
+			}
+		      catch (IOException e)
+			{
+			  dumpElementln ("no, got IOException");
+			}
+		    }
+		}
+
+	      this.currentObject = null;
+	      this.currentObjectStreamClass = null;
+	      ret_val = processResolution (obj, handle);
+	      break;
+	    }
+	    
+	  case TC_RESET:
+	    dumpElementln ("RESET");
+	    clearHandles ();
+	    ret_val = readObject ();
+	    break;
+	    
+	  case TC_EXCEPTION:
+	    {
+	      dumpElement ("EXCEPTION=");
+	      Exception e = (Exception)readObject ();
+	      dumpElementln (e.toString());
+	      clearHandles ();
+	      throw new WriteAbortedException ("Exception thrown during writing of stream", e);
+	    }
+	      
+	  default:
+	    throw new IOException ("Unknown marker on stream: " + marker);
 
-	  // XXX: should initialize fields in classes in the hierarchy
-	  // that aren't in the stream
-	  // should skip over classes in the stream that aren't in the
-	  // real classes hierarchy
-	  readFields (obj, this.currentObjectStreamClass.fields,
-		      has_read, this.currentObjectStreamClass);
-
-	  if (has_read)
-	  {
-	    dumpElement ("ENDBLOCKDATA? ");
-	    try
-	      {
-		// FIXME: XXX: This try block is to catch EOF which is
-		// thrown for some objects.  That indicates a bug in the logic.
-	        if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
-		  throw new IOException ("No end of block data seen for class with readObject (ObjectInputStream) method.");
-	        dumpElementln ("yes");
-	      }
-	    catch (EOFException e)
-	      {
-	        dumpElementln ("no, got EOFException");
-	      }
-	    catch (IOException e)
-	      {
-	        dumpElementln ("no, got IOException");
-	      }
 	  }
-	}
-
-	this.currentObject = null;
-	this.currentObjectStreamClass = null;
-	ret_val = processResolution (obj, handle);
-	break;
       }
-
-      case TC_RESET:
-	dumpElementln ("RESET");
-	clearHandles ();
-	ret_val = readObject ();
-	break;
-
-      case TC_EXCEPTION:
+    finally
       {
-	dumpElement ("EXCEPTION=");
-	Exception e = (Exception)readObject ();
-	dumpElementln (e.toString());
-	clearHandles ();
-	throw new WriteAbortedException ("Exception thrown during writing of stream", e);
+	setBlockDataMode (old_mode);
+	
+	this.isDeserializing = was_deserializing;
+	
+	if (! was_deserializing)
+	  {
+	    if (validators.size () > 0)
+	      invokeValidators ();
+	  }
       }
-
-      default:
-	throw new IOException ("Unknown marker on stream");
-    }
-
-    this.isDeserializing = was_deserializing;
-
-    if (! was_deserializing)
-    {
-      setBlockDataMode (true);
-
-      if (validators.size () > 0)
-	invokeValidators ();
-    }
-
+    
     return ret_val;
   }
-
+	
 
   /**
      Reads the current objects non-transient, non-static fields from
@@ -439,9 +494,11 @@
     if (fieldsAlreadyRead)
       throw new NotActiveException ("defaultReadObject called but fields already read from stream (by defaultReadObject or readFields)");
 
+    boolean oldmode = setBlockDataMode(false);
     readFields (this.currentObject,
 		this.currentObjectStreamClass.fields,
 		false, this.currentObjectStreamClass);
+    setBlockDataMode(oldmode);
 
     fieldsAlreadyRead = true;
   }
@@ -500,13 +557,18 @@
     throws ClassNotFoundException, IOException
   {
     SecurityManager sm = System.getSecurityManager ();
+    if (sm == null)
+      sm = new SecurityManager () {};
 
     // FIXME: currentClassLoader doesn't yet do anything useful. We need
     // to call forName() with the classloader of the class which called 
     // readObject(). See SecurityManager.getClassContext().
     ClassLoader cl = currentClassLoader (sm);
 
-    return Class.forName (osc.getName (), true, cl);
+    if (cl == null)
+      return Class.forName (osc.getName ());
+    else
+      return cl.loadClass (osc.getName ());
   }
 
   /**
@@ -617,7 +679,17 @@
     if (this.readDataFromBlock)
     {
       if (this.blockDataPosition + length > this.blockDataBytes)
-	readNextBlock ();
+	{
+	  int remain = this.blockDataBytes - this.blockDataPosition;
+	  if (remain != 0)
+	    {
+	      System.arraycopy (this.blockData, this.blockDataPosition,
+				data, offset, remain);
+	      offset += remain;
+	      length -= remain;
+	    }
+	  readNextBlock ();
+	}
 
       System.arraycopy (this.blockData, this.blockDataPosition,
 			data, offset, length);
@@ -785,11 +857,11 @@
     // Apparently Block data is not used with GetField as per
     // empirical evidence against JDK 1.2.  Also see Mauve test
     // java.io.ObjectInputOutput.Test.GetPutField.
-    setBlockDataMode (false);
+    boolean oldmode = setBlockDataMode (false);
     readFully (prim_field_data);
     for (int i = 0; i < objs.length; ++ i)
       objs[i] = readObject ();
-    setBlockDataMode (true);
+    setBlockDataMode (oldmode);
 
     return new GetField ()
     {
@@ -990,7 +1062,7 @@
      de serialization mechanism provided by
      <code>ObjectInputStream</code>.  To make this method be used for
      writing objects, subclasses must invoke the 0-argument
-     constructor on this class from there constructor.
+     constructor on this class from their constructor.
 
      @see ObjectInputStream ()
   */
@@ -1175,9 +1247,9 @@
     {
 //    DEBUGln ("  call_read_method is true");
       fieldsAlreadyRead = false;
-      setBlockDataMode (true);
+      boolean oldmode = setBlockDataMode (true);
       callReadMethod (obj, stream_osc.forClass ());
-      setBlockDataMode (false);
+      setBlockDataMode (oldmode);
       return;
     }
 
@@ -1237,101 +1309,109 @@
 	}
       }
 
-      if (type == Boolean.TYPE)
-      {
-	boolean value =
-	  default_initialize ? false : this.realInputStream.readBoolean ();
-	if (!default_initialize && set_value)
-	  dumpElementln ("  " + field_name + ": " + value);
-	if (set_value)
-	  setBooleanField (obj, field_name, value);
-      }
-      else if (type == Byte.TYPE)
-      {
-	byte value =
-	  default_initialize ? 0 : this.realInputStream.readByte ();
-	if (!default_initialize && set_value)
-	  dumpElementln ("  " + field_name + ": " + value);
-	if (set_value)
-	  setByteField (obj, field_name, value);
-      }
-      else if (type == Character.TYPE)
-      {
-	char value =
-	  default_initialize ? (char)0 : this.realInputStream.readChar ();
-	if (!default_initialize && set_value)
-	  dumpElementln ("  " + field_name + ": " + value);
-	if (set_value)
-	  setCharField (obj, field_name, value);
-      }
-      else if (type == Double.TYPE)
-      {
-	double value =
-	  default_initialize ? 0 : this.realInputStream.readDouble ();
-	if (!default_initialize && set_value)
-	  dumpElementln ("  " + field_name + ": " + value);
-	if (set_value)
-	  setDoubleField (obj, field_name, value);
-      }
-      else if (type == Float.TYPE)
-      {
-	float value =
-	  default_initialize ? 0 : this.realInputStream.readFloat ();
-	if (!default_initialize && set_value)
-	  dumpElementln ("  " + field_name + ": " + value);
-	if (set_value)
-	  setFloatField (obj, field_name, value);
-      }
-      else if (type == Integer.TYPE)
-      {
-	int value =
-	  default_initialize ? 0 : this.realInputStream.readInt ();
-	if (!default_initialize && set_value)
-	  dumpElementln ("  " + field_name + ": " + value);
-	if (set_value)
-	  setIntField (obj, field_name, value);
-      }
-      else if (type == Long.TYPE)
-      {
-	long value =
-	  default_initialize ? 0 : this.realInputStream.readLong ();
-	if (!default_initialize && set_value)
-	  dumpElementln ("  " + field_name + ": " + value);
-	if (set_value)
-	  setLongField (obj, field_name, value);
-      }
-      else if (type == Short.TYPE)
-      {
-	short value =
-	  default_initialize ? (short)0 : this.realInputStream.readShort ();
-	if (!default_initialize && set_value)
-	  dumpElementln ("  " + field_name + ": " + value);
-	if (set_value)
-	  setShortField (obj, field_name, value);
-      }
-      else
-      {
-	Object value =
-	  default_initialize ? null : readObject ();
-	if (set_value)
-	  setObjectField (obj, field_name,
-			  real_field.getTypeString (), value);
-      }
+      try
+	{
+	  if (type == Boolean.TYPE)
+	    {
+	      boolean value =
+		default_initialize ? false : this.realInputStream.readBoolean ();
+	      if (!default_initialize && set_value)
+		dumpElementln ("  " + field_name + ": " + value);
+	      if (set_value)
+		setBooleanField (obj, field_name, value);
+	    }
+	  else if (type == Byte.TYPE)
+	    {
+	      byte value =
+		default_initialize ? 0 : this.realInputStream.readByte ();
+	      if (!default_initialize && set_value)
+		dumpElementln ("  " + field_name + ": " + value);
+	      if (set_value)
+		setByteField (obj, field_name, value);
+	    }
+	  else if (type == Character.TYPE)
+	    {
+	      char value =
+		default_initialize ? (char)0 : this.realInputStream.readChar ();
+	      if (!default_initialize && set_value)
+		dumpElementln ("  " + field_name + ": " + value);
+	      if (set_value)
+		setCharField (obj, field_name, value);
+	    }
+	  else if (type == Double.TYPE)
+	    {
+	      double value =
+		default_initialize ? 0 : this.realInputStream.readDouble ();
+	      if (!default_initialize && set_value)
+		dumpElementln ("  " + field_name + ": " + value);
+	      if (set_value)
+		setDoubleField (obj, field_name, value);
+	    }
+	  else if (type == Float.TYPE)
+	    {
+	      float value =
+		default_initialize ? 0 : this.realInputStream.readFloat ();
+	      if (!default_initialize && set_value)
+		dumpElementln ("  " + field_name + ": " + value);
+	      if (set_value)
+		setFloatField (obj, field_name, value);
+	    }
+	  else if (type == Integer.TYPE)
+	    {
+	      int value =
+		default_initialize ? 0 : this.realInputStream.readInt ();
+	      if (!default_initialize && set_value)
+		dumpElementln ("  " + field_name + ": " + value);
+	      if (set_value)
+		setIntField (obj, field_name, value);
+	    }
+	  else if (type == Long.TYPE)
+	    {
+	      long value =
+		default_initialize ? 0 : this.realInputStream.readLong ();
+	      if (!default_initialize && set_value)
+		dumpElementln ("  " + field_name + ": " + value);
+	      if (set_value)
+		setLongField (obj, field_name, value);
+	    }
+	  else if (type == Short.TYPE)
+	    {
+	      short value =
+		default_initialize ? (short)0 : this.realInputStream.readShort ();
+	      if (!default_initialize && set_value)
+		dumpElementln ("  " + field_name + ": " + value);
+	      if (set_value)
+		setShortField (obj, field_name, value);
+	    }
+	  else
+	    {
+	      Object value =
+		default_initialize ? null : readObject ();
+	      if (set_value)
+		setObjectField (obj, field_name,
+				real_field.getTypeString (), value);
+	    }
+	}
+      catch (NoSuchFieldError e)
+	{
+	  dumpElementln("XXXX " + field_name + " does not exist.");
+	}
     }
   }
 
 
   // Toggles writing primitive data to block-data buffer.
-  private void setBlockDataMode (boolean on)
+  private boolean setBlockDataMode (boolean on)
   {
 //    DEBUGln ("Setting block data mode to " + on);
-
+    boolean oldmode = this.readDataFromBlock;
     this.readDataFromBlock = on;
 
     if (on)
       this.dataInputStream = this.blockDataInput;
     else
       this.dataInputStream = this.realInputStream;
+    return oldmode;
   }
 
 
@@ -1380,12 +1460,18 @@
     return ClassLoader.getSystemClassLoader ();
   }
 
-  private static native Field getField (Class klass, String name)
-    throws java.lang.NoSuchFieldException;
-
-  private static native Method getMethod (Class klass, String name, Class args[])
-    throws java.lang.NoSuchMethodException;
-
+  private static Field getField (Class klass, String name)
+    throws java.lang.NoSuchFieldException
+  {
+    return klass.getDeclaredField(name);
+  }
+                                                                                
+  private static Method getMethod (Class klass, String name, Class args[])
+    throws java.lang.NoSuchMethodException
+  {
+    return klass.getDeclaredMethod(name, args);
+  }
+                                                                                
   private void callReadMethod (Object obj, Class klass) throws IOException
   {
     try
@@ -1593,6 +1679,14 @@
     if (Configuration.DEBUG && dump)
       System.out.println(msg);
   }
+
+  static
+    {
+      if (Configuration.INIT_LOAD_LIBRARY)
+	{
+	  System.loadLibrary ("javaio");
+	}
+    }
 }
 
 
Index: java/io/ObjectOutputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectOutputStream.java,v
retrieving revision 1.10
diff -u -r1.10 ObjectOutputStream.java
--- java/io/ObjectOutputStream.java	22 Jan 2002 22:40:14 -0000	1.10
+++ java/io/ObjectOutputStream.java	23 Feb 2003 15:55:38 -0000
@@ -1,5 +1,5 @@
 /* ObjectOutputStream.java -- Class used to write serialized objects
-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -46,6 +46,7 @@
 
 import gnu.java.io.ObjectIdentityWrapper;
 import gnu.java.lang.reflect.TypeSignature;
+import gnu.classpath.Configuration;
 
 /**
    An <code>ObjectOutputStream</code> can be used to write objects
@@ -167,229 +168,242 @@
   public final void writeObject (Object obj) throws IOException
   {
     if (useSubclassMethod)
-    {
-      writeObjectOverride (obj);
-      return;
-    }
+      {
+	writeObjectOverride (obj);
+	return;
+      }
 
     boolean was_serializing = isSerializing;
-
-    if (! was_serializing)
-      setBlockDataMode (false);
-
+    boolean old_mode = setBlockDataMode (false);
     try
-    {
-      isSerializing = true;
-      boolean replaceDone = false;
-
-      drain ();
-
-      while (true)
       {
-	if (obj == null)
-	{
-	  realOutput.writeByte (TC_NULL);
-	  break;
-	}
-
-	Integer handle = findHandle (obj);
-	if (handle != null)
-	{
-	  realOutput.writeByte (TC_REFERENCE);
-	  realOutput.writeInt (handle.intValue ());
-	  break;
-	}
-
-	if (obj instanceof Class)
-	{
-	  realOutput.writeByte (TC_CLASS);
-	  writeObject (ObjectStreamClass.lookup ((Class)obj));
-	  assignNewHandle (obj);
-	  break;
-	}
-
-	if (obj instanceof ObjectStreamClass)
-	{
-	  ObjectStreamClass osc = (ObjectStreamClass)obj;
-	  realOutput.writeByte (TC_CLASSDESC);
-	  realOutput.writeUTF (osc.getName ());
-	  realOutput.writeLong (osc.getSerialVersionUID ());
-	  assignNewHandle (obj);
-
-	  int flags = osc.getFlags ();
-
-	  if (protocolVersion == PROTOCOL_VERSION_2
-	      && osc.isExternalizable ())
-	    flags |= SC_BLOCK_DATA;
-
-	  realOutput.writeByte (flags);
-
-	  ObjectStreamField[] fields = osc.fields;
-	  realOutput.writeShort (fields.length);
-
-	  ObjectStreamField field;
-	  for (int i=0; i < fields.length; i++)
-	  {
-	    field = fields[i];
-	    realOutput.writeByte (field.getTypeCode ());
-	    realOutput.writeUTF (field.getName ());
-
-	    if (! field.isPrimitive ())
-	      writeObject (field.getTypeString ());
-	  }
-
-	  setBlockDataMode (true);
-	  annotateClass (osc.forClass ());
-	  setBlockDataMode (false);
-	  realOutput.writeByte (TC_ENDBLOCKDATA);
-
-	  if (osc.isSerializable ())
-	    writeObject (osc.getSuper ());
-	  else
-	    writeObject (null);
-	  break;
-	}
-
-
+	isSerializing = true;
+	boolean replaceDone = false;
 	Object replacedObject = null;
-
-	if ((replacementEnabled || obj instanceof Serializable)
-	    && ! replaceDone)
-	{
-	  replacedObject = obj;
-
-	  if (obj instanceof Serializable)
-	    {
-	      Method m = null;
-	      try
+	
+	while (true)
+	  {
+	    if (obj == null)
 	      {
-	        Class classArgs[] = {};
-		m = obj.getClass ().getDeclaredMethod ("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[] {});
+		realOutput.writeByte (TC_NULL);
+		break;
 	      }
-	      catch (NoSuchMethodException ignore)
+	    
+	    Integer handle = findHandle (obj);
+	    if (handle != null)
 	      {
+		realOutput.writeByte (TC_REFERENCE);
+		realOutput.writeInt (handle.intValue ());
+		break;
 	      }
-	      catch (IllegalAccessException ignore)
+	    
+	    if (obj instanceof Class)
 	      {
+		Class cl = (Class)obj;
+		ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl);
+		assignNewHandle (obj);
+		realOutput.writeByte (TC_CLASS);
+		if (!osc.isProxyClass)
+		  {
+		    writeObject(osc);
+		  }
+		else
+		  {
+		    realOutput.writeByte (TC_PROXYCLASSDESC);
+		    Class[] intfs = cl.getInterfaces();
+		    realOutput.writeInt(intfs.length);
+		    for (int i = 0; i < intfs.length; i++)
+		      realOutput.writeUTF(intfs[i].getName());
+		    
+		    boolean oldmode = setBlockDataMode (true);
+		    annotateProxyClass(cl);
+		    setBlockDataMode (oldmode);
+		    realOutput.writeByte(TC_ENDBLOCKDATA);
+		    
+		    writeObject (osc.getSuper());
+		  }
+		break;
 	      }
-	      catch (InvocationTargetException ignore)
+	    
+	    if (obj instanceof ObjectStreamClass)
 	      {
+		ObjectStreamClass osc = (ObjectStreamClass)obj;
+		realOutput.writeByte (TC_CLASSDESC);
+		realOutput.writeUTF (osc.getName ());
+		realOutput.writeLong (osc.getSerialVersionUID ());
+		assignNewHandle (obj);
+		
+		int flags = osc.getFlags ();
+		
+		if (protocolVersion == PROTOCOL_VERSION_2
+		    && osc.isExternalizable ())
+		  flags |= SC_BLOCK_DATA;
+		
+		realOutput.writeByte (flags);
+		
+		ObjectStreamField[] fields = osc.fields;
+		realOutput.writeShort (fields.length);
+		
+		ObjectStreamField field;
+		for (int i=0; i < fields.length; i++)
+		  {
+		    field = fields[i];
+		    realOutput.writeByte (field.getTypeCode ());
+		    realOutput.writeUTF (field.getName ());
+		    
+		    if (! field.isPrimitive ())
+		      writeObject (field.getTypeString ());
+		  }
+		
+		boolean oldmode = setBlockDataMode (true);
+		annotateClass (osc.forClass ());
+		setBlockDataMode (oldmode);
+		realOutput.writeByte (TC_ENDBLOCKDATA);
+		
+		if (osc.isSerializable ())
+		  writeObject (osc.getSuper ());
+		else
+		  writeObject (null);
+		break;
 	      }
-	    }
-
-	  if (replacementEnabled)
-	    obj = replaceObject (obj);
-
-	  replaceDone = true;
-	  continue;
-	}
-
-	if (obj instanceof String)
-	{
-	  realOutput.writeByte (TC_STRING);
-	  assignNewHandle (obj);
-	  realOutput.writeUTF ((String)obj);
-	  break;
-	}
-
-	Class clazz = obj.getClass ();
-	ObjectStreamClass osc = ObjectStreamClass.lookup (clazz);
-	if (osc == null)
-	  throw new NotSerializableException (clazz.getName ());
-
-	if (clazz.isArray ())
-	{
-	  realOutput.writeByte (TC_ARRAY);
-	  writeObject (osc);
-	  assignNewHandle (obj);
-	  writeArraySizeAndElements (obj, clazz.getComponentType ());
-	  break;
-	}
-
-	realOutput.writeByte (TC_OBJECT);
-	writeObject (osc);
-
-	if (replaceDone)
-	  assignNewHandle (replacedObject);
-	else
-	  assignNewHandle (obj);
-
-	if (obj instanceof Externalizable)
-	{
-	  if (protocolVersion == PROTOCOL_VERSION_2)
-	    setBlockDataMode (true);
-
-	  ((Externalizable)obj).writeExternal (this);
+	    
+	    if ((replacementEnabled || obj instanceof Serializable)
+		&& ! replaceDone)
+	      {
+		replacedObject = obj;
+		
+		if (obj instanceof Serializable)
+		  {
+		    Method m = null;
+		    try
+		      {
+			Class classArgs[] = {};
+			m = obj.getClass ().getDeclaredMethod ("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)
+		      {
+		      }
+		    catch (IllegalAccessException ignore)
+		      {
+		      }
+		    catch (InvocationTargetException ignore)
+		      {
+		      }
+		  }
+		
+		if (replacementEnabled)
+		  obj = replaceObject (obj);
+		
+		replaceDone = true;
+		continue;
+	      }
+	    
+	    if (obj instanceof String)
+	      {
+		realOutput.writeByte (TC_STRING);
+		assignNewHandle (obj);
+		realOutput.writeUTF ((String)obj);
+		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);
+		writeObject (osc);
+		assignNewHandle (obj);
+		writeArraySizeAndElements (obj, clazz.getComponentType ());
+		break;
+	      }
+	    
+	    realOutput.writeByte (TC_OBJECT);
+	    writeObject (osc);
+	    
+	    if (replaceDone)
+	      assignNewHandle (replacedObject);
+	    else
+	      assignNewHandle (obj);
+	    
+	    if (obj instanceof Externalizable)
+	      {
+		if (protocolVersion == PROTOCOL_VERSION_2)
+		  setBlockDataMode (true);
+		
+		((Externalizable)obj).writeExternal (this);
+		
+		if (protocolVersion == PROTOCOL_VERSION_2)
+		  {
+		    setBlockDataMode (false);
+		    realOutput.writeByte (TC_ENDBLOCKDATA);
+		  }
+		
+		break;
+	      }
+	    
+	    if (obj instanceof Serializable)
+	      {
+		currentObject = obj;
+		ObjectStreamClass[] hierarchy =
+		  ObjectStreamClass.getObjectStreamClasses (clazz);
+		
+		boolean has_write;
+		for (int i=0; i < hierarchy.length; i++)
+		  {
+		    currentObjectStreamClass = hierarchy[i];
+		    
+		    fieldsAlreadyWritten = false;
+		    has_write = currentObjectStreamClass.hasWriteMethod ();
+		    
+		    writeFields (obj, currentObjectStreamClass.fields,
+				 has_write);
+		    
+		  }
+		
+		currentObject = null;
+		currentObjectStreamClass = null;
+		currentPutField = null;
+		break;
+	      }
+	    
+	    throw new NotSerializableException (clazz.getName ());
+	  } // end pseudo-loop
+      }
+    catch (ObjectStreamException ose)
+      {
+	// Rethrow these are fatal.
+	throw ose;
+      }
+    catch (IOException e)
+      {
+	realOutput.writeByte (TC_EXCEPTION);
+	reset (true);
 
-	  if (protocolVersion == PROTOCOL_VERSION_2)
+	setBlockDataMode (false);
+	try
 	  {
-	    setBlockDataMode (false);
-	    drain ();
+	    writeObject (e);
 	  }
-
-	  break;
-	}
-
-	if (obj instanceof Serializable)
-	{
-	  currentObject = obj;
-	  ObjectStreamClass[] hierarchy =
-	    ObjectStreamClass.getObjectStreamClasses (clazz);
-
-	  boolean has_write;
-	  for (int i=0; i < hierarchy.length; i++)
+	catch (IOException ioe)
 	  {
-	    currentObjectStreamClass = hierarchy[i];
-
-	    fieldsAlreadyWritten = false;
-	    has_write = currentObjectStreamClass.hasWriteMethod ();
-
-	    writeFields (obj, currentObjectStreamClass.fields,
-			 has_write);
-
-	    if (has_write)
-	    {
-	      drain ();
-	      realOutput.writeByte (TC_ENDBLOCKDATA);
-	    }
+	    throw new StreamCorruptedException ("Exception " + ioe + " thrown while exception was being written to stream.");
 	  }
-
-	  currentObject = null;
-	  currentObjectStreamClass = null;
-	  currentPutField = null;
-	  break;
-	}
-
-	throw new NotSerializableException (clazz.getName ());
-      } // end pseudo-loop
-    }
-    catch (IOException e)
-    {
-      realOutput.writeByte (TC_EXCEPTION);
-      reset (true);
-
-      try
-      {
-	writeObject (e);
-      }
-      catch (IOException ioe)
-      {
-	throw new StreamCorruptedException ("Exception " + ioe + " thrown while exception was being written to stream.");
+	
+	reset (true);
       }
-
-      reset (true);
-    }
     finally
-    {
-      isSerializing = was_serializing;
+      {
+	isSerializing = was_serializing;
 
-      if (! was_serializing)
-	setBlockDataMode (true);
-    }
+	setBlockDataMode (old_mode);
+      }
   }
 
 
@@ -466,8 +480,8 @@
      according to the specified protocol.  There are currently two
      different protocols, specified by <code>PROTOCOL_VERSION_1</code>
      and <code>PROTOCOL_VERSION_2</code>.  This implementation writes
-     data using <code>PROTOCOL_VERSION_1</code> by default, as is done
-     by the JDK 1.1.
+     data using <code>PROTOCOL_VERSION_2</code> by default, as is done
+     by the JDK 1.2.
 
      A non-portable method, <code>setDefaultProtocolVersion (int
      version)</code> is provided to change the default protocol
@@ -528,6 +542,8 @@
   protected void annotateClass (Class cl) throws IOException
   {}
 
+  protected void annotateProxyClass(Class cl) throws IOException
+  {}
 
   /**
      Allows subclasses to replace objects that are written to the
@@ -702,7 +718,8 @@
     if (blockDataCount == 0)
       return;
 
-    writeBlockDataHeader (blockDataCount);
+    if (writeDataAsBlocks)
+      writeBlockDataHeader (blockDataCount);
     realOutput.write (blockData, 0, blockDataCount);
     blockDataCount = 0;
   }
@@ -713,7 +730,7 @@
   */
   public void close () throws IOException
   {
-    drain ();
+    flush ();
     realOutput.close ();
   }
 
@@ -723,7 +740,7 @@
   */
   public void writeBoolean (boolean data) throws IOException
   {
-    dataOutput.writeBoolean (data);
+    blockDataOutput.writeBoolean (data);
   }
 
 
@@ -732,7 +749,7 @@
   */
   public void writeByte (int data) throws IOException
   {
-    dataOutput.writeByte (data);
+    blockDataOutput.writeByte (data);
   }
 
 
@@ -741,7 +758,7 @@
   */
   public void writeShort (int data) throws IOException
   {
-    dataOutput.writeShort (data);
+    blockDataOutput.writeShort (data);
   }
 
 
@@ -750,7 +767,7 @@
   */
   public void writeChar (int data) throws IOException
   {
-    dataOutput.writeChar (data);
+    blockDataOutput.writeChar (data);
   }
 
 
@@ -759,7 +776,7 @@
   */
   public void writeInt (int data) throws IOException
   {
-    dataOutput.writeInt (data);
+    blockDataOutput.writeInt (data);
   }
 
 
@@ -768,7 +785,7 @@
   */
   public void writeLong (long data) throws IOException
   {
-    dataOutput.writeLong (data);
+    blockDataOutput.writeLong (data);
   }
 
 
@@ -777,7 +794,7 @@
   */
   public void writeFloat (float data) throws IOException
   {
-    dataOutput.writeFloat (data);
+    blockDataOutput.writeFloat (data);
   }
 
 
@@ -786,7 +803,7 @@
   */
   public void writeDouble (double data) throws IOException
   {
-    dataOutput.writeDouble (data);
+    blockDataOutput.writeDouble (data);
   }
 
 
@@ -795,7 +812,7 @@
   */
   public void writeBytes (String data) throws IOException
   {
-    dataOutput.writeBytes (data);
+    blockDataOutput.writeBytes (data);
   }
 
 
@@ -965,6 +983,8 @@
 	  {
 	    ObjectStreamField field
 	      = currentObjectStreamClass.getField (name);
+	    if (field == null)
+	      throw new IllegalArgumentException ();
 	    if (value != null &&
 	    	! field.getType ().isAssignableFrom (value.getClass ()))
 	      throw new IllegalArgumentException ();
@@ -976,11 +996,11 @@
 	    // Apparently Block data is not used with PutField as per
 	    // empirical evidence against JDK 1.2.  Also see Mauve test
 	    // java.io.ObjectInputOutput.Test.GetPutField.
-	    setBlockDataMode (false);
+	    boolean oldmode = setBlockDataMode (false);
 	    out.write (prim_field_data);
 	    for (int i = 0; i < objs.length; ++ i)
 	      out.writeObject (objs[i]);
-	    setBlockDataMode (true);
+	    setBlockDataMode (oldmode);
 	  }
 
 	private void checkType (ObjectStreamField field, char type)
@@ -1067,8 +1087,7 @@
       {
 	byte[] cast_array = (byte[])array;
 	realOutput.writeInt (length);
-	for (int i=0; i < length; i++)
-	  realOutput.writeByte (cast_array[i]);
+	realOutput.write(cast_array, 0, length);
 	return;
       }
       if (clazz == Character.TYPE)
@@ -1142,9 +1161,11 @@
       setBlockDataMode (true);
       callWriteMethod (obj);
       setBlockDataMode (false);
+      realOutput.writeByte (TC_ENDBLOCKDATA);
       return;
     }
 
+    boolean oldmode = setBlockDataMode (false);
     String field_name;
     Class type;
     for (int i=0; i < fields.length; i++)
@@ -1170,20 +1191,28 @@
 	realOutput.writeShort (getShortField (obj, field_name));
       else
 	writeObject (getObjectField (obj, field_name,
-				     TypeSignature.getEncodingOfClass (type)));
+				     fields[i].getTypeString ()));
     }
+    setBlockDataMode(oldmode);
   }
 
 
   // Toggles writing primitive data to block-data buffer.
-  private void setBlockDataMode (boolean on)
+  private boolean setBlockDataMode (boolean on) throws IOException
   {
+    if (on == writeDataAsBlocks)
+      return on;
+
+    drain();
+    boolean oldmode = writeDataAsBlocks;
     writeDataAsBlocks = on;
 
     if (on)
       dataOutput = blockDataOutput;
     else
       dataOutput = realOutput;
+
+    return oldmode;
   }
 
 
@@ -1355,16 +1384,22 @@
       }    
   }
 
-  private static native Field getField (Class klass, String name)
-    throws java.lang.NoSuchFieldException;
-
-  private static native Method getMethod (Class klass, String name, Class[] args)
-    throws java.lang.NoSuchMethodException;
-
+  private static Field getField (Class klass, String name)
+    throws java.lang.NoSuchFieldException
+  {
+    return klass.getDeclaredField(name);
+  }
+                                                                                
+  private static Method getMethod (Class klass, String name, Class[] args)
+    throws java.lang.NoSuchMethodException
+  {
+    return klass.getDeclaredMethod(name, args);
+  }
+                                                                                
   // this value comes from 1.2 spec, but is used in 1.1 as well
   private final static int BUFFER_SIZE = 1024;
 
-  private static int defaultProtocolVersion = PROTOCOL_VERSION_1;
+  private static int defaultProtocolVersion = PROTOCOL_VERSION_2;
 
   private DataOutputStream dataOutput;
   private boolean writeDataAsBlocks;
@@ -1382,4 +1417,12 @@
   private Hashtable OIDLookupTable;
   private int protocolVersion;
   private boolean useSubclassMethod;
+
+  static
+  {
+    if (Configuration.INIT_LOAD_LIBRARY)
+      {
+        System.loadLibrary ("javaio");
+      }
+  }
 }
Index: java/io/ObjectStreamField.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectStreamField.java,v
retrieving revision 1.2
diff -u -r1.2 ObjectStreamField.java
--- java/io/ObjectStreamField.java	22 Jan 2002 22:40:14 -0000	1.2
+++ java/io/ObjectStreamField.java	23 Feb 2003 15:55:38 -0000
@@ -47,8 +47,23 @@
   {
     this.name = name;
     this.type = type;
+    this.typename = TypeSignature.getEncodingOfClass(type);
   }
-
+ 
+  /**
+   * There're many cases you can't get java.lang.Class from typename if your context
+   * class loader can't load it, then use typename to construct the field
+   */
+  ObjectStreamField (String name, String typename){
+    this.name = name;
+    this.typename = typename;
+    try{
+      type = TypeSignature.getClassForEncoding(typename);
+    }catch(ClassNotFoundException e){
+      type = Object.class; //??
+    }
+  }
+  
   public String getName ()
   {
     return name;
@@ -61,12 +76,13 @@
 
   public char getTypeCode ()
   {
-    return TypeSignature.getEncodingOfClass (type).charAt (0);
+    return typename.charAt (0);
   }
 
   public String getTypeString ()
   {
-    return TypeSignature.getEncodingOfClass (type);
+    // use intern()
+    return typename.intern();
   }
 
   public int getOffset ()
@@ -106,5 +122,6 @@
 
   private String name;
   private Class type;
+  private String typename;
   private int offset = -1; // XXX make sure this is correct
 }
Index: java/io/natObjectInputStream.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/natObjectInputStream.cc,v
retrieving revision 1.5
diff -u -r1.5 natObjectInputStream.cc
--- java/io/natObjectInputStream.cc	9 Dec 2001 00:17:07 -0000	1.5
+++ java/io/natObjectInputStream.cc	23 Feb 2003 15:55:38 -0000
@@ -69,16 +69,3 @@
 				+ m->offset);
   _Jv_CallAnyMethodA (obj, JvPrimClass (void), meth, false, arg_types, NULL);
 }
-  
-java::lang::reflect::Field *
-java::io::ObjectInputStream::getField (jclass klass, jstring name)
-{
-  return klass->getPrivateField (name);
-}
-
-java::lang::reflect::Method *
-java::io::ObjectInputStream::getMethod (jclass klass, jstring name, 
-					JArray<jclass> *arg_types)
-{
-  return klass->getPrivateMethod (name, arg_types);
-}
Index: java/io/natObjectOutputStream.cc
===================================================================
RCS file: java/io/natObjectOutputStream.cc
diff -N java/io/natObjectOutputStream.cc
--- java/io/natObjectOutputStream.cc	19 May 2000 17:55:31 -0000	1.1
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,33 +0,0 @@
-// natObjectOutputStream.cc - Native part of ObjectOutputStream class.
-
-/* Copyright (C) 1998, 1999  Free Software Foundation
-
-   This ObjectOutputStream is part of libgcj.
-
-This software is copyrighted work licensed under the terms of the
-Libgcj License.  Please consult the ObjectOutputStream "LIBGCJ_LICENSE" for
-details.  */
-
-#include <config.h>
-
-#include <gcj/cni.h>
-#include <jvm.h>
-#include <java/io/ObjectOutputStream$PutField.h>
-#include <java/io/ObjectOutputStream.h>
-#include <java/io/IOException.h>
-#include <java/lang/Class.h>
-
-
-java::lang::reflect::Field *
-java::io::ObjectOutputStream::getField (jclass klass, jstring name)
-{
-  return klass->getPrivateField (name);
-}
-
-java::lang::reflect::Method *
-java::io::ObjectOutputStream::getMethod (jclass klass, jstring name, 
-					 JArray<jclass> *arg_types)
-{
-  return klass->getPrivateMethod (name, arg_types);
-}
-

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