8256480: Refactor ObjectInputStream field reader implementation

Reviewed-by: bchristi
This commit is contained in:
Roger Riggs 2020-11-24 17:04:08 +00:00
parent 1c4c99eae2
commit bd14274b1b

View File

@ -653,10 +653,12 @@ public class ObjectInputStream
Object curObj = ctx.getObj();
ObjectStreamClass curDesc = ctx.getDesc();
bin.setBlockDataMode(false);
FieldValues vals = defaultReadFields(curObj, curDesc);
// Read fields of the current descriptor into a new FieldValues
FieldValues values = new FieldValues(curDesc, true);
if (curObj != null) {
defaultCheckFieldValues(curObj, curDesc, vals);
defaultSetFieldValues(curObj, curDesc, vals);
values.defaultCheckFieldValues(curObj);
values.defaultSetFieldValues(curObj);
}
bin.setBlockDataMode(true);
if (!curDesc.hasWriteObjectData()) {
@ -696,8 +698,8 @@ public class ObjectInputStream
ctx.checkAndSetUsed();
ObjectStreamClass curDesc = ctx.getDesc();
bin.setBlockDataMode(false);
GetFieldImpl getField = new GetFieldImpl(curDesc);
getField.readFields();
// Read fields of the current descriptor into a new FieldValues
FieldValues values = new FieldValues(curDesc, false);
bin.setBlockDataMode(true);
if (!curDesc.hasWriteObjectData()) {
/*
@ -707,8 +709,7 @@ public class ObjectInputStream
*/
defaultDataEnd = true;
}
return getField;
return values;
}
/**
@ -2322,14 +2323,13 @@ public class ObjectInputStream
if (slots.length != 1) {
// skip any superclass stream field values
for (int i = 0; i < slots.length-1; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
if (slots[i].hasData) {
defaultReadFields(null, slotDesc);
new FieldValues(slots[i].desc, true);
}
}
}
FieldValues fieldValues = defaultReadFields(null, desc);
FieldValues fieldValues = new FieldValues(desc, true);
// get canonical record constructor adapted to take two arguments:
// - byte[] primValues
@ -2388,7 +2388,8 @@ public class ObjectInputStream
if (slots[i].hasData) {
if (obj == null || handles.lookupException(passHandle) != null) {
defaultReadFields(null, slotDesc); // skip field values
// Read fields of the current descriptor into a new FieldValues and discard
new FieldValues(slotDesc, true);
} else if (slotDesc.hasReadObjectMethod()) {
ThreadDeath t = null;
boolean reset = false;
@ -2432,12 +2433,13 @@ public class ObjectInputStream
*/
defaultDataEnd = false;
} else {
FieldValues vals = defaultReadFields(obj, slotDesc);
// Read fields of the current descriptor into a new FieldValues
FieldValues values = new FieldValues(slotDesc, true);
if (slotValues != null) {
slotValues[i] = vals;
slotValues[i] = values;
} else if (obj != null) {
defaultCheckFieldValues(obj, slotDesc, vals);
defaultSetFieldValues(obj, slotDesc, vals);
values.defaultCheckFieldValues(obj);
values.defaultSetFieldValues(obj);
}
}
@ -2461,11 +2463,11 @@ public class ObjectInputStream
// before assigning.
for (int i = 0; i < slots.length; i++) {
if (slotValues[i] != null)
defaultCheckFieldValues(obj, slots[i].desc, slotValues[i]);
slotValues[i].defaultCheckFieldValues(obj);
}
for (int i = 0; i < slots.length; i++) {
if (slotValues[i] != null)
defaultSetFieldValues(obj, slots[i].desc, slotValues[i]);
slotValues[i].defaultSetFieldValues(obj);
}
}
}
@ -2499,76 +2501,6 @@ public class ObjectInputStream
}
}
/*package-private*/ class FieldValues {
final byte[] primValues;
final Object[] objValues;
FieldValues(byte[] primValues, Object[] objValues) {
this.primValues = primValues;
this.objValues = objValues;
}
}
/**
* Reads in values of serializable fields declared by given class
* descriptor. Expects that passHandle is set to obj's handle before this
* method is called.
*/
private FieldValues defaultReadFields(Object obj, ObjectStreamClass desc)
throws IOException
{
Class<?> cl = desc.forClass();
if (cl != null && obj != null && !cl.isInstance(obj)) {
throw new ClassCastException();
}
byte[] primVals = null;
int primDataSize = desc.getPrimDataSize();
if (primDataSize > 0) {
primVals = new byte[primDataSize];
bin.readFully(primVals, 0, primDataSize, false);
}
Object[] objVals = null;
int numObjFields = desc.getNumObjFields();
if (numObjFields > 0) {
int objHandle = passHandle;
ObjectStreamField[] fields = desc.getFields(false);
objVals = new Object[numObjFields];
int numPrimFields = fields.length - objVals.length;
for (int i = 0; i < objVals.length; i++) {
ObjectStreamField f = fields[numPrimFields + i];
objVals[i] = readObject0(Object.class, f.isUnshared());
if (f.getField() != null) {
handles.markDependency(objHandle, passHandle);
}
}
passHandle = objHandle;
}
return new FieldValues(primVals, objVals);
}
/** Throws ClassCastException if any value is not assignable. */
private void defaultCheckFieldValues(Object obj, ObjectStreamClass desc,
FieldValues values) {
Object[] objectValues = values.objValues;
if (objectValues != null)
desc.checkObjFieldValueTypes(obj, objectValues);
}
/** Sets field values in obj. */
private void defaultSetFieldValues(Object obj, ObjectStreamClass desc,
FieldValues values) {
byte[] primValues = values.primValues;
Object[] objectValues = values.objValues;
if (primValues != null)
desc.setPrimFieldValues(obj, primValues);
if (objectValues != null)
desc.setObjFieldValues(obj, objectValues);
}
/**
* Reads in and returns IOException that caused serialization to abort.
* All stream state is discarded prior to reading in fatal exception. Sets
@ -2608,103 +2540,123 @@ public class ObjectInputStream
/**
* Default GetField implementation.
*/
private class GetFieldImpl extends GetField {
private final class FieldValues extends GetField {
/** class descriptor describing serializable fields */
private final ObjectStreamClass desc;
/** primitive field values */
private final byte[] primVals;
final byte[] primValues;
/** object field values */
private final Object[] objVals;
final Object[] objValues;
/** object field value handles */
private final int[] objHandles;
/**
* Creates GetFieldImpl object for reading fields defined in given
* Creates FieldValues object for reading fields defined in given
* class descriptor.
* @param desc the ObjectStreamClass to read
* @param recordDependencies if true, record the dependencies
* from current PassHandle and the object's read.
*/
GetFieldImpl(ObjectStreamClass desc) {
FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws IOException {
this.desc = desc;
primVals = new byte[desc.getPrimDataSize()];
objVals = new Object[desc.getNumObjFields()];
objHandles = new int[objVals.length];
int primDataSize = desc.getPrimDataSize();
primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
if (primDataSize > 0) {
bin.readFully(primValues, 0, primDataSize, false);
}
int numObjFields = desc.getNumObjFields();
objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
if (numObjFields > 0) {
int objHandle = passHandle;
ObjectStreamField[] fields = desc.getFields(false);
int numPrimFields = fields.length - objValues.length;
for (int i = 0; i < objValues.length; i++) {
ObjectStreamField f = fields[numPrimFields + i];
objValues[i] = readObject0(Object.class, f.isUnshared());
objHandles[i] = passHandle;
if (recordDependencies && f.getField() != null) {
handles.markDependency(objHandle, passHandle);
}
}
passHandle = objHandle;
}
}
public ObjectStreamClass getObjectStreamClass() {
return desc;
}
public boolean defaulted(String name) throws IOException {
public boolean defaulted(String name) {
return (getFieldOffset(name, null) < 0);
}
public boolean get(String name, boolean val) throws IOException {
public boolean get(String name, boolean val) {
int off = getFieldOffset(name, Boolean.TYPE);
return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
return (off >= 0) ? Bits.getBoolean(primValues, off) : val;
}
public byte get(String name, byte val) throws IOException {
public byte get(String name, byte val) {
int off = getFieldOffset(name, Byte.TYPE);
return (off >= 0) ? primVals[off] : val;
return (off >= 0) ? primValues[off] : val;
}
public char get(String name, char val) throws IOException {
public char get(String name, char val) {
int off = getFieldOffset(name, Character.TYPE);
return (off >= 0) ? Bits.getChar(primVals, off) : val;
return (off >= 0) ? Bits.getChar(primValues, off) : val;
}
public short get(String name, short val) throws IOException {
public short get(String name, short val) {
int off = getFieldOffset(name, Short.TYPE);
return (off >= 0) ? Bits.getShort(primVals, off) : val;
return (off >= 0) ? Bits.getShort(primValues, off) : val;
}
public int get(String name, int val) throws IOException {
public int get(String name, int val) {
int off = getFieldOffset(name, Integer.TYPE);
return (off >= 0) ? Bits.getInt(primVals, off) : val;
return (off >= 0) ? Bits.getInt(primValues, off) : val;
}
public float get(String name, float val) throws IOException {
public float get(String name, float val) {
int off = getFieldOffset(name, Float.TYPE);
return (off >= 0) ? Bits.getFloat(primVals, off) : val;
return (off >= 0) ? Bits.getFloat(primValues, off) : val;
}
public long get(String name, long val) throws IOException {
public long get(String name, long val) {
int off = getFieldOffset(name, Long.TYPE);
return (off >= 0) ? Bits.getLong(primVals, off) : val;
return (off >= 0) ? Bits.getLong(primValues, off) : val;
}
public double get(String name, double val) throws IOException {
public double get(String name, double val) {
int off = getFieldOffset(name, Double.TYPE);
return (off >= 0) ? Bits.getDouble(primVals, off) : val;
return (off >= 0) ? Bits.getDouble(primValues, off) : val;
}
public Object get(String name, Object val) throws IOException {
public Object get(String name, Object val) {
int off = getFieldOffset(name, Object.class);
if (off >= 0) {
int objHandle = objHandles[off];
handles.markDependency(passHandle, objHandle);
return (handles.lookupException(objHandle) == null) ?
objVals[off] : null;
objValues[off] : null;
} else {
return val;
}
}
/**
* Reads primitive and object field values from stream.
*/
void readFields() throws IOException {
bin.readFully(primVals, 0, primVals.length, false);
/** Throws ClassCastException if any value is not assignable. */
void defaultCheckFieldValues(Object obj) {
if (objValues != null)
desc.checkObjFieldValueTypes(obj, objValues);
}
int oldHandle = passHandle;
ObjectStreamField[] fields = desc.getFields(false);
int numPrimFields = fields.length - objVals.length;
for (int i = 0; i < objVals.length; i++) {
objVals[i] =
readObject0(Object.class, fields[numPrimFields + i].isUnshared());
objHandles[i] = passHandle;
}
passHandle = oldHandle;
private void defaultSetFieldValues(Object obj) {
if (primValues != null)
desc.setPrimFieldValues(obj, primValues);
if (objValues != null)
desc.setObjFieldValues(obj, objValues);
}
/**