Hashtable patch, more serialization patches
Jose Orlando Pereira
jop at di.uminho.pt
Thu Feb 4 09:44:57 PST 1999
Hi,
There seems to be a bug in java.lang.Hashtable that is triggered when,
after being used for a while, all free slots are marked as "removed".
The first patch below corrects this problem.
The second patch is a rather large patch to object streams which:
- corrects the bug I described yesterday (demonstrated by
Alias.java), by introducing kaffe.util.IdentityHashtable (is
kaffe.util the right place for this stuff?) and using it instead
of a regular Hashtable in ObjectOutputStream;
- substitutes Vector for Hashtable in ObjectInputStream, which
increases performance of deserialization;
- corrects another bug related to serializing deep class hierarchies
which use alternating readObject/writeObject and default serialization
strategies.
The current snapshot with these patches (and the multicast related one
I sent earlier) enables Kaffe to run my app, making me a happy man. :-)
--
Jose Orlando Pereira
* mailto:jop at di.uminho.pt * http://gsd.di.uminho.pt/~jop *
-------------- next part --------------
diff -Nru kaffe-snap/libraries/javalib/java/util/Hashtable.java kaffe-snap-jop/libraries/javalib/java/util/Hashtable.java
--- kaffe-snap/libraries/javalib/java/util/Hashtable.java Sun Dec 13 22:11:53 1998
+++ kaffe-snap-jop/libraries/javalib/java/util/Hashtable.java Thu Feb 4 15:43:37 1999
@@ -206,6 +206,12 @@
return (null);
}
}
+ if (space != -1) {
+ keys[space] = key;
+ elements[space] = value;
+ numberOfKeys++;
+ return (null);
+ }
// We shouldn't get here.
throw new Error("Inconsistent Hashtable");
}
-------------- next part --------------
diff -Nru kaffe-snap/libraries/javalib/java/io/ObjectInputStream.java kaffe-snap-jop/libraries/javalib/java/io/ObjectInputStream.java
--- kaffe-snap/libraries/javalib/java/io/ObjectInputStream.java Wed Feb 3 21:02:09 1999
+++ kaffe-snap-jop/libraries/javalib/java/io/ObjectInputStream.java Thu Feb 4 16:52:15 1999
@@ -12,7 +12,7 @@
import java.lang.String;
import java.io.Serializable;
-import java.util.Hashtable;
+import java.util.Vector;
import kaffe.util.NotImplemented;
public class ObjectInputStream
@@ -25,8 +25,8 @@
private int pos = 0;
private int len = 0;
private boolean doBlocking = false;
-private Hashtable objectsDone = new Hashtable();
-private int nextKey = 0x007e0000;
+private Vector objectsDone = new Vector();
+private static final int firstKey = 0x007e0001;
private Object currObject;
private ObjectStreamClass currStreamClass;
private boolean enableResolve = false;
@@ -190,8 +190,7 @@
int tok = readUnsignedByte();
if (tok == ObjectStreamConstants.TC_REFERENCE) {
- Integer key = new Integer(readInt());
- currObject = objectsDone.get(key);
+ currObject = objectsDone.elementAt(readInt()-firstKey);
if (currObject == null) {
throw new StreamCorruptedException("reference to unknown object");
}
@@ -209,23 +208,16 @@
throw new StreamCorruptedException("expected class desc");
}
currObject = allocateNewObject(currStreamClass.clazz, null);
- Integer key = new Integer(++nextKey);
- objectsDone.put(key, currObject);
+ objectsDone.addElement(currObject);
if ((currStreamClass.method & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0) {
- try {
- ((Externalizable)currObject).readExternal(this);
- }
- catch (ClassCastException _) {
- }
- }
- else if ((currStreamClass.method & ObjectStreamConstants.SC_WRRD_METHODS) != 0) {
- invokeObjectReader(currObject, currObject.getClass());
- }
- else if ((currStreamClass.method & ObjectStreamConstants.SC_SERIALIZABLE) != 0) {
- defaultReadObject();
+ try {
+ ((Externalizable)currObject).readExternal(this);
+ }
+ catch (ClassCastException _) {
+ }
}
else {
- throw new StreamCorruptedException("unknown method type: " + currStreamClass.method);
+ readDataFields(currStreamClass, currObject);
}
break;
@@ -242,8 +234,7 @@
case ObjectStreamConstants.TC_CLASSDESC:
ObjectStreamClass cls = new ObjectStreamClass();
currObject = (Object)cls;
- Integer key = new Integer(++nextKey);
- objectsDone.put(key, currObject);
+ objectsDone.addElement(currObject);
invokeObjectReader(currObject, ObjectStreamClass.class);
cls.clazz = resolveClass(cls);
cls.buildFieldsAndOffset();
@@ -251,14 +242,13 @@
case ObjectStreamConstants.TC_STRING:
currObject = readUTF();
- Integer key = new Integer(++nextKey);
- objectsDone.put(key, currObject);
+ objectsDone.addElement(currObject);
break;
case ObjectStreamConstants.TC_RESET:
pos = 0;
len = 0;
- objectsDone = new Hashtable();
+ objectsDone = new Vector();
enableBuffering(true);
break;
@@ -283,14 +273,23 @@
public final void defaultReadObject() throws IOException, ClassNotFoundException, NotActiveException
{
- readDataFields(currStreamClass, currObject);
+ inputClassFields(currObject, currStreamClass.clazz, currStreamClass.fieldRdWr);
}
-private void readDataFields(ObjectStreamClass strm, Object obj)
+private void readDataFields(ObjectStreamClass strm, Object obj) throws IOException, ClassNotFoundException
{
if (strm != null) {
readDataFields(strm.superclazzStream, obj);
- inputClassFields(obj, strm.clazz, strm.fieldRdWr);
+ ObjectStreamClass oldStreamClass = currStreamClass;
+ currStreamClass = strm;
+ if ((strm.method & ObjectStreamConstants.SC_WRRD_METHODS) != 0) {
+ invokeObjectReader(obj, strm.clazz);
+ }
+ else if ((strm.method & ObjectStreamConstants.SC_SERIALIZABLE) != 0) {
+ defaultReadObject();
+ } else
+ throw new StreamCorruptedException("unknown method type: " + strm.method);
+ currStreamClass = oldStreamClass;
}
}
@@ -314,8 +313,7 @@
{
int len = readInt();
Object obj = allocateNewArray(currStreamClass.clazz, len);
- Integer key = new Integer(++nextKey);
- objectsDone.put(key, obj);
+ objectsDone.addElement(obj);
Class elem = currStreamClass.clazz.getComponentType();
if (elem == Object.class) {
diff -Nru kaffe-snap/libraries/javalib/java/io/ObjectOutputStream.java kaffe-snap-jop/libraries/javalib/java/io/ObjectOutputStream.java
--- kaffe-snap/libraries/javalib/java/io/ObjectOutputStream.java Wed Dec 9 23:20:12 1998
+++ kaffe-snap-jop/libraries/javalib/java/io/ObjectOutputStream.java Thu Feb 4 16:52:22 1999
@@ -12,7 +12,7 @@
import java.lang.String;
import java.io.Serializable;
-import java.util.Hashtable;
+import kaffe.util.IdentityHashtable;
import kaffe.util.NotImplemented;
public class ObjectOutputStream
@@ -26,7 +26,7 @@
private OutputStream out;
private byte[] outBuf = new byte[255];
private int pos = 0;
-private Hashtable objectsDone = new Hashtable();
+private IdentityHashtable objectsDone = new IdentityHashtable();
private int nextKey = 0x007e0000;
private boolean doBlocking = false;
private boolean enableReplace = false;
@@ -88,7 +88,7 @@
throw new IOException("currently serializing object");
}
enableBuffering(false);
- objectsDone = new Hashtable();
+ objectsDone = new IdentityHashtable();
pos = 0;
writeByte(ObjectStreamConstants.TC_RESET);
enableBuffering(false);
@@ -265,24 +265,21 @@
key = new Integer(++nextKey);
objectsDone.put(obj, key);
- if ((currStreamClass.method & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0) {
+ if (currStreamClass.clazz.isArray()) {
+ writeArray(currStreamClass, currObject);
+ }
+ else if ((currStreamClass.method & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0) {
try {
((Externalizable)obj).writeExternal(this);
}
catch (ClassCastException _) {
}
}
- else if ((currStreamClass.method & ObjectStreamConstants.SC_WRRD_METHODS) != 0) {
- invokeObjectWriter(obj, cls);
- }
- else if ((currStreamClass.method & ObjectStreamConstants.SC_SERIALIZABLE) != 0) {
- defaultWriteObject();
- }
else if ((currStreamClass.method & ObjectStreamConstants.SC_STRING) != 0) {
writeUTF((String)obj);
}
else {
- throw new StreamCorruptedException("unknown method type");
+ writeDataFields(currStreamClass, currObject);
}
// Write any annotations.
annotateClass(currStreamClass.clazz);
@@ -303,22 +300,25 @@
if (currObject == null) {
throw new NotActiveException();
}
- if (currStreamClass.clazz.isArray()) {
- writeArray(currStreamClass, currObject);
- }
- else {
- writeDataFields(currStreamClass, currObject);
- }
+ outputClassFields(currObject, currStreamClass.clazz, currStreamClass.fieldRdWr);
}
}
-private void writeDataFields(ObjectStreamClass strm, Object obj)
+private void writeDataFields(ObjectStreamClass strm, Object obj) throws IOException
{
if (strm == null) {
return;
}
writeDataFields(strm.superclazzStream, obj);
- outputClassFields(obj, strm.clazz, strm.fieldRdWr);
+ ObjectStreamClass oldStreamClass = currStreamClass;
+ currStreamClass = strm;
+ if ((strm.method & ObjectStreamConstants.SC_WRRD_METHODS) != 0) {
+ invokeObjectWriter(obj, strm.clazz);
+ }
+ else if ((strm.method & ObjectStreamConstants.SC_SERIALIZABLE) != 0) {
+ defaultWriteObject();
+ }
+ currStreamClass = oldStreamClass;
}
private void writeArray(ObjectStreamClass strm, Object obj) throws IOException
diff -Nru kaffe-snap/libraries/javalib/kaffe/util/IdentityHastable.java kaffe-snap-jop/libraries/javalib/kaffe/util/IdentityHastable.java
--- kaffe-snap/libraries/javalib/kaffe/util/IdentityHastable.java Thu Jan 1 01:00:00 1970
+++ kaffe-snap-jop/libraries/javalib/kaffe/util/IdentityHastable.java Thu Feb 4 15:43:26 1999
@@ -0,0 +1,227 @@
+/*
+ * Java core library component.
+ *
+ * Copyright (c) 1997, 1998
+ * Transvirtual Technologies, Inc. All rights reserved.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file.
+ */
+
+package kaffe.util;
+
+import java.lang.String;
+import java.util.NoSuchElementException;
+
+/* IdentityHashtable is a simplified java.util.Hashtable for use by
+ java.io.ObjectOutputStream. It uses System.identityHashCode and
+ == instead of hashCode() and equals(). */
+
+public class IdentityHashtable {
+ transient private Object keys[];
+ transient private Object elements[];
+ transient private float loadFactor;
+ private int numberOfKeys;
+ transient private int rehashLimit;
+
+ private static final int DEFAULTCAPACITY = 101;
+ private static final float DEFAULTLOADFACTOR = (float)0.75;
+ private static final Object removed = new Object();
+ private static final Object free = null;
+
+ public IdentityHashtable() {
+ this(DEFAULTCAPACITY, DEFAULTLOADFACTOR);
+ }
+
+ public IdentityHashtable(int initialCapacity) {
+ this(initialCapacity, DEFAULTLOADFACTOR);
+ }
+
+ public IdentityHashtable(int initialCapacity, float loadFactor)
+ {
+ if (initialCapacity <= 0) {
+ throw new Error("Initial capacity is <= 0");
+ }
+ if (loadFactor <= 0.0) {
+ throw new Error("Load Factor is <= 0");
+ }
+ this.loadFactor = loadFactor;
+ this.keys = new Object[initialCapacity];
+ this.elements = new Object[initialCapacity];
+ this.numberOfKeys = 0;
+ this.rehashLimit = (int)(loadFactor * (float)initialCapacity);
+ }
+
+ public int size() {
+ return (numberOfKeys);
+ }
+
+ public boolean isEmpty() {
+ return (numberOfKeys == 0);
+ }
+
+ public synchronized boolean contains(Object value) {
+ for (int pos = elements.length-1; pos >= 0; pos--) {
+ if (value.equals(elements[pos])) {
+ return (true);
+ }
+ }
+ return false;
+ }
+
+ public synchronized boolean containsKey(Object key) {
+ return (get(key) != null);
+ }
+
+ private int calculateBucket(Object key) {
+ return ((System.identityHashCode(key) & Integer.MAX_VALUE) % keys.length);
+ }
+
+ public synchronized Object get(Object key)
+ {
+ int posn = calculateBucket(key);
+ int limit = keys.length;
+ for (int i = posn; i < limit; i++) {
+ Object mkey = keys[i];
+ if (key==mkey) {
+ return (elements[i]);
+ }
+ if (mkey == free) {
+ return (null);
+ }
+ }
+ for (int i = 0; i < posn; i++) {
+ Object mkey = keys[i];
+ if (key==mkey) {
+ return (elements[i]);
+ }
+ if (mkey == free) {
+ return (null);
+ }
+ }
+ return (null);
+ }
+
+ protected synchronized void rehash()
+ {
+ int newCapacity = keys.length * 2;
+ Object oldKeys[] = keys;
+ Object oldElements[] = elements;
+
+ keys = new Object[newCapacity];
+ elements = new Object[newCapacity];
+ rehashLimit = (int)(loadFactor * (float)newCapacity);
+ numberOfKeys = 0;
+
+ /* Go through adding all the data to the new data */
+ for (int pos = oldKeys.length-1; pos >= 0; pos--) {
+ if (oldKeys[pos] != free && oldKeys[pos] != removed) {
+ put(oldKeys[pos], oldElements[pos]);
+ }
+ }
+ }
+
+ public synchronized Object put(Object key, Object value) {
+ if (numberOfKeys >= rehashLimit) {
+ rehash();
+ }
+
+ int posn = calculateBucket(key);
+ int limit = keys.length;
+ int space = -1;
+ for (int i = posn; i < limit; i++) {
+ Object mkey = keys[i];
+ if (key==mkey) {
+ Object oldElement = elements[i];
+ elements[i] = value;
+ return (oldElement);
+ }
+ if (mkey == removed) {
+ if (space == -1) {
+ space = i;
+ }
+ }
+ else if (mkey == free) {
+ if (space == -1) {
+ space = i;
+ }
+ keys[space] = key;
+ elements[space] = value;
+ numberOfKeys++;
+ return (null);
+ }
+ }
+ for (int i = 0; i < posn; i++) {
+ Object mkey = keys[i];
+ if (key==mkey) {
+ Object oldElement = elements[i];
+ elements[i] = value;
+ return (oldElement);
+ }
+ if (mkey == removed) {
+ if (space == -1) {
+ space = i;
+ }
+ }
+ else if (mkey == free) {
+ if (space == -1) {
+ space = i;
+ }
+ keys[space] = key;
+ elements[space] = value;
+ numberOfKeys++;
+ return (null);
+ }
+ }
+ if (space != -1) {
+ keys[space] = key;
+ elements[space] = value;
+ numberOfKeys++;
+ return (null);
+ }
+ // We shouldn't get here.
+ throw new Error("Inconsistent IdentityHashtable");
+ }
+
+ public synchronized Object remove(Object key) {
+
+ int posn = calculateBucket(key);
+ int limit = keys.length;
+ for (int i = posn; i < limit; i++) {
+ Object mkey = keys[i];
+ if (key==mkey) {
+ Object oldElement = elements[i];
+ elements[i] = removed;
+ keys[i] = removed;
+ numberOfKeys--;
+ return (oldElement);
+ }
+ if (mkey == free) {
+ return (null);
+ }
+ }
+ for (int i = 0; i < posn; i++) {
+ Object mkey = keys[i];
+ if (key==mkey) {
+ Object oldElement = elements[i];
+ elements[i] = removed;
+ keys[i] = removed;
+ numberOfKeys--;
+ return (oldElement);
+ }
+ if (mkey == free) {
+ return (null);
+ }
+ }
+ return (null);
+ }
+
+ public synchronized void clear() {
+ for (int pos = keys.length - 1; pos >= 0; pos--) {
+ keys[pos] = free;
+ elements[pos] = free;
+ }
+ numberOfKeys = 0;
+ }
+}
+
More information about the kaffe
mailing list