1 /*
   2  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.io;
  27 
  28 import java.io.ObjectStreamClass.WeakClassKey;
  29 import java.lang.ref.ReferenceQueue;
  30 import java.lang.reflect.Array;
  31 import java.lang.reflect.Modifier;
  32 import java.lang.reflect.Proxy;
  33 import java.security.AccessControlContext;
  34 import java.security.AccessController;
  35 import java.security.PrivilegedAction;
  36 import java.security.PrivilegedActionException;
  37 import java.security.PrivilegedExceptionAction;
  38 import java.util.Arrays;
  39 import java.util.HashMap;
  40 import java.util.concurrent.ConcurrentHashMap;
  41 import java.util.concurrent.ConcurrentMap;
  42 import static java.io.ObjectStreamClass.processQueue;
  43 import jdk.internal.misc.Unsafe;
  44 import sun.reflect.misc.ReflectUtil;
  45 
  46 /**
  47  * An ObjectInputStream deserializes primitive data and objects previously
  48  * written using an ObjectOutputStream.
  49  *
  50  * <p>ObjectOutputStream and ObjectInputStream can provide an application with
  51  * persistent storage for graphs of objects when used with a FileOutputStream
  52  * and FileInputStream respectively.  ObjectInputStream is used to recover
  53  * those objects previously serialized. Other uses include passing objects
  54  * between hosts using a socket stream or for marshaling and unmarshaling
  55  * arguments and parameters in a remote communication system.
  56  *
  57  * <p>ObjectInputStream ensures that the types of all objects in the graph
  58  * created from the stream match the classes present in the Java Virtual
  59  * Machine.  Classes are loaded as required using the standard mechanisms.
  60  *
  61  * <p>Only objects that support the java.io.Serializable or
  62  * java.io.Externalizable interface can be read from streams.
  63  *
  64  * <p>The method <code>readObject</code> is used to read an object from the
  65  * stream.  Java's safe casting should be used to get the desired type.  In
  66  * Java, strings and arrays are objects and are treated as objects during
  67  * serialization. When read they need to be cast to the expected type.
  68  *
  69  * <p>Primitive data types can be read from the stream using the appropriate
  70  * method on DataInput.
  71  *
  72  * <p>The default deserialization mechanism for objects restores the contents
  73  * of each field to the value and type it had when it was written.  Fields
  74  * declared as transient or static are ignored by the deserialization process.
  75  * References to other objects cause those objects to be read from the stream
  76  * as necessary.  Graphs of objects are restored correctly using a reference
  77  * sharing mechanism.  New objects are always allocated when deserializing,
  78  * which prevents existing objects from being overwritten.
  79  *
  80  * <p>Reading an object is analogous to running the constructors of a new
  81  * object.  Memory is allocated for the object and initialized to zero (NULL).
  82  * No-arg constructors are invoked for the non-serializable classes and then
  83  * the fields of the serializable classes are restored from the stream starting
  84  * with the serializable class closest to java.lang.object and finishing with
  85  * the object's most specific class.
  86  *
  87  * <p>For example to read from a stream as written by the example in
  88  * ObjectOutputStream:
  89  * <br>
  90  * <pre>
  91  *      FileInputStream fis = new FileInputStream("t.tmp");
  92  *      ObjectInputStream ois = new ObjectInputStream(fis);
  93  *
  94  *      int i = ois.readInt();
  95  *      String today = (String) ois.readObject();
  96  *      Date date = (Date) ois.readObject();
  97  *
  98  *      ois.close();
  99  * </pre>
 100  *
 101  * <p>Classes control how they are serialized by implementing either the
 102  * java.io.Serializable or java.io.Externalizable interfaces.
 103  *
 104  * <p>Implementing the Serializable interface allows object serialization to
 105  * save and restore the entire state of the object and it allows classes to
 106  * evolve between the time the stream is written and the time it is read.  It
 107  * automatically traverses references between objects, saving and restoring
 108  * entire graphs.
 109  *
 110  * <p>Serializable classes that require special handling during the
 111  * serialization and deserialization process should implement the following
 112  * methods:
 113  *
 114  * <pre>
 115  * private void writeObject(java.io.ObjectOutputStream stream)
 116  *     throws IOException;
 117  * private void readObject(java.io.ObjectInputStream stream)
 118  *     throws IOException, ClassNotFoundException;
 119  * private void readObjectNoData()
 120  *     throws ObjectStreamException;
 121  * </pre>
 122  *
 123  * <p>The readObject method is responsible for reading and restoring the state
 124  * of the object for its particular class using data written to the stream by
 125  * the corresponding writeObject method.  The method does not need to concern
 126  * itself with the state belonging to its superclasses or subclasses.  State is
 127  * restored by reading data from the ObjectInputStream for the individual
 128  * fields and making assignments to the appropriate fields of the object.
 129  * Reading primitive data types is supported by DataInput.
 130  *
 131  * <p>Any attempt to read object data which exceeds the boundaries of the
 132  * custom data written by the corresponding writeObject method will cause an
 133  * OptionalDataException to be thrown with an eof field value of true.
 134  * Non-object reads which exceed the end of the allotted data will reflect the
 135  * end of data in the same way that they would indicate the end of the stream:
 136  * bytewise reads will return -1 as the byte read or number of bytes read, and
 137  * primitive reads will throw EOFExceptions.  If there is no corresponding
 138  * writeObject method, then the end of default serialized data marks the end of
 139  * the allotted data.
 140  *
 141  * <p>Primitive and object read calls issued from within a readExternal method
 142  * behave in the same manner--if the stream is already positioned at the end of
 143  * data written by the corresponding writeExternal method, object reads will
 144  * throw OptionalDataExceptions with eof set to true, bytewise reads will
 145  * return -1, and primitive reads will throw EOFExceptions.  Note that this
 146  * behavior does not hold for streams written with the old
 147  * <code>ObjectStreamConstants.PROTOCOL_VERSION_1</code> protocol, in which the
 148  * end of data written by writeExternal methods is not demarcated, and hence
 149  * cannot be detected.
 150  *
 151  * <p>The readObjectNoData method is responsible for initializing the state of
 152  * the object for its particular class in the event that the serialization
 153  * stream does not list the given class as a superclass of the object being
 154  * deserialized.  This may occur in cases where the receiving party uses a
 155  * different version of the deserialized instance's class than the sending
 156  * party, and the receiver's version extends classes that are not extended by
 157  * the sender's version.  This may also occur if the serialization stream has
 158  * been tampered; hence, readObjectNoData is useful for initializing
 159  * deserialized objects properly despite a "hostile" or incomplete source
 160  * stream.
 161  *
 162  * <p>Serialization does not read or assign values to the fields of any object
 163  * that does not implement the java.io.Serializable interface.  Subclasses of
 164  * Objects that are not serializable can be serializable. In this case the
 165  * non-serializable class must have a no-arg constructor to allow its fields to
 166  * be initialized.  In this case it is the responsibility of the subclass to
 167  * save and restore the state of the non-serializable class. It is frequently
 168  * the case that the fields of that class are accessible (public, package, or
 169  * protected) or that there are get and set methods that can be used to restore
 170  * the state.
 171  *
 172  * <p>Any exception that occurs while deserializing an object will be caught by
 173  * the ObjectInputStream and abort the reading process.
 174  *
 175  * <p>Implementing the Externalizable interface allows the object to assume
 176  * complete control over the contents and format of the object's serialized
 177  * form.  The methods of the Externalizable interface, writeExternal and
 178  * readExternal, are called to save and restore the objects state.  When
 179  * implemented by a class they can write and read their own state using all of
 180  * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
 181  * the objects to handle any versioning that occurs.
 182  *
 183  * <p>Enum constants are deserialized differently than ordinary serializable or
 184  * externalizable objects.  The serialized form of an enum constant consists
 185  * solely of its name; field values of the constant are not transmitted.  To
 186  * deserialize an enum constant, ObjectInputStream reads the constant name from
 187  * the stream; the deserialized constant is then obtained by calling the static
 188  * method <code>Enum.valueOf(Class, String)</code> with the enum constant's
 189  * base type and the received constant name as arguments.  Like other
 190  * serializable or externalizable objects, enum constants can function as the
 191  * targets of back references appearing subsequently in the serialization
 192  * stream.  The process by which enum constants are deserialized cannot be
 193  * customized: any class-specific readObject, readObjectNoData, and readResolve
 194  * methods defined by enum types are ignored during deserialization.
 195  * Similarly, any serialPersistentFields or serialVersionUID field declarations
 196  * are also ignored--all enum types have a fixed serialVersionUID of 0L.
 197  *
 198  * @author      Mike Warres
 199  * @author      Roger Riggs
 200  * @see java.io.DataInput
 201  * @see java.io.ObjectOutputStream
 202  * @see java.io.Serializable
 203  * @see <a href="../../../platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
 204  * @since   1.1
 205  */
 206 public class ObjectInputStream
 207     extends InputStream implements ObjectInput, ObjectStreamConstants
 208 {
 209     /** handle value representing null */
 210     private static final int NULL_HANDLE = -1;
 211 
 212     /** marker for unshared objects in internal handle table */
 213     private static final Object unsharedMarker = new Object();
 214 
 215     /** table mapping primitive type names to corresponding class objects */
 216     private static final HashMap<String, Class<?>> primClasses
 217         = new HashMap<>(8, 1.0F);
 218     static {
 219         primClasses.put("boolean", boolean.class);
 220         primClasses.put("byte", byte.class);
 221         primClasses.put("char", char.class);
 222         primClasses.put("short", short.class);
 223         primClasses.put("int", int.class);
 224         primClasses.put("long", long.class);
 225         primClasses.put("float", float.class);
 226         primClasses.put("double", double.class);
 227         primClasses.put("void", void.class);
 228     }
 229 
 230     private static class Caches {
 231         /** cache of subclass security audit results */
 232         static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
 233             new ConcurrentHashMap<>();
 234 
 235         /** queue for WeakReferences to audited subclasses */
 236         static final ReferenceQueue<Class<?>> subclassAuditsQueue =
 237             new ReferenceQueue<>();
 238     }
 239 
 240     /** filter stream for handling block data conversion */
 241     private final BlockDataInputStream bin;
 242     /** validation callback list */
 243     private final ValidationList vlist;
 244     /** recursion depth */
 245     private int depth;
 246     /** whether stream is closed */
 247     private boolean closed;
 248 
 249     /** wire handle -> obj/exception map */
 250     private final HandleTable handles;
 251     /** scratch field for passing handle values up/down call stack */
 252     private int passHandle = NULL_HANDLE;
 253     /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
 254     private boolean defaultDataEnd = false;
 255 
 256     /** if true, invoke readObjectOverride() instead of readObject() */
 257     private final boolean enableOverride;
 258     /** if true, invoke resolveObject() */
 259     private boolean enableResolve;
 260 
 261     /**
 262      * Context during upcalls to class-defined readObject methods; holds
 263      * object currently being deserialized and descriptor for current class.
 264      * Null when not during readObject upcall.
 265      */
 266     private SerialCallbackContext curContext;
 267 
 268     /**
 269      * Creates an ObjectInputStream that reads from the specified InputStream.
 270      * A serialization stream header is read from the stream and verified.
 271      * This constructor will block until the corresponding ObjectOutputStream
 272      * has written and flushed the header.
 273      *
 274      * <p>If a security manager is installed, this constructor will check for
 275      * the "enableSubclassImplementation" SerializablePermission when invoked
 276      * directly or indirectly by the constructor of a subclass which overrides
 277      * the ObjectInputStream.readFields or ObjectInputStream.readUnshared
 278      * methods.
 279      *
 280      * @param   in input stream to read from
 281      * @throws  StreamCorruptedException if the stream header is incorrect
 282      * @throws  IOException if an I/O error occurs while reading stream header
 283      * @throws  SecurityException if untrusted subclass illegally overrides
 284      *          security-sensitive methods
 285      * @throws  NullPointerException if <code>in</code> is <code>null</code>
 286      * @see     ObjectInputStream#ObjectInputStream()
 287      * @see     ObjectInputStream#readFields()
 288      * @see     ObjectOutputStream#ObjectOutputStream(OutputStream)
 289      */
 290     public ObjectInputStream(InputStream in) throws IOException {
 291         verifySubclass();
 292         bin = new BlockDataInputStream(in);
 293         handles = new HandleTable(10);
 294         vlist = new ValidationList();
 295         enableOverride = false;
 296         readStreamHeader();
 297         bin.setBlockDataMode(true);
 298     }
 299 
 300     /**
 301      * Provide a way for subclasses that are completely reimplementing
 302      * ObjectInputStream to not have to allocate private data just used by this
 303      * implementation of ObjectInputStream.
 304      *
 305      * <p>If there is a security manager installed, this method first calls the
 306      * security manager's <code>checkPermission</code> method with the
 307      * <code>SerializablePermission("enableSubclassImplementation")</code>
 308      * permission to ensure it's ok to enable subclassing.
 309      *
 310      * @throws  SecurityException if a security manager exists and its
 311      *          <code>checkPermission</code> method denies enabling
 312      *          subclassing.
 313      * @throws  IOException if an I/O error occurs while creating this stream
 314      * @see SecurityManager#checkPermission
 315      * @see java.io.SerializablePermission
 316      */
 317     protected ObjectInputStream() throws IOException, SecurityException {
 318         SecurityManager sm = System.getSecurityManager();
 319         if (sm != null) {
 320             sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
 321         }
 322         bin = null;
 323         handles = null;
 324         vlist = null;
 325         enableOverride = true;
 326     }
 327 
 328     /**
 329      * Read an object from the ObjectInputStream.  The class of the object, the
 330      * signature of the class, and the values of the non-transient and
 331      * non-static fields of the class and all of its supertypes are read.
 332      * Default deserializing for a class can be overriden using the writeObject
 333      * and readObject methods.  Objects referenced by this object are read
 334      * transitively so that a complete equivalent graph of objects is
 335      * reconstructed by readObject.
 336      *
 337      * <p>The root object is completely restored when all of its fields and the
 338      * objects it references are completely restored.  At this point the object
 339      * validation callbacks are executed in order based on their registered
 340      * priorities. The callbacks are registered by objects (in the readObject
 341      * special methods) as they are individually restored.
 342      *
 343      * <p>Exceptions are thrown for problems with the InputStream and for
 344      * classes that should not be deserialized.  All exceptions are fatal to
 345      * the InputStream and leave it in an indeterminate state; it is up to the
 346      * caller to ignore or recover the stream state.
 347      *
 348      * @throws  ClassNotFoundException Class of a serialized object cannot be
 349      *          found.
 350      * @throws  InvalidClassException Something is wrong with a class used by
 351      *          serialization.
 352      * @throws  StreamCorruptedException Control information in the
 353      *          stream is inconsistent.
 354      * @throws  OptionalDataException Primitive data was found in the
 355      *          stream instead of objects.
 356      * @throws  IOException Any of the usual Input/Output related exceptions.
 357      */
 358     public final Object readObject()
 359         throws IOException, ClassNotFoundException
 360     {
 361         if (enableOverride) {
 362             return readObjectOverride();
 363         }
 364 
 365         // if nested read, passHandle contains handle of enclosing object
 366         int outerHandle = passHandle;
 367         try {
 368             Object obj = readObject0(false);
 369             handles.markDependency(outerHandle, passHandle);
 370             ClassNotFoundException ex = handles.lookupException(passHandle);
 371             if (ex != null) {
 372                 throw ex;
 373             }
 374             if (depth == 0) {
 375                 vlist.doCallbacks();
 376                 freeze();
 377             }
 378             return obj;
 379         } finally {
 380             passHandle = outerHandle;
 381             if (closed && depth == 0) {
 382                 clear();
 383             }
 384         }
 385     }
 386 
 387     /**
 388      * This method is called by trusted subclasses of ObjectOutputStream that
 389      * constructed ObjectOutputStream using the protected no-arg constructor.
 390      * The subclass is expected to provide an override method with the modifier
 391      * "final".
 392      *
 393      * @return  the Object read from the stream.
 394      * @throws  ClassNotFoundException Class definition of a serialized object
 395      *          cannot be found.
 396      * @throws  OptionalDataException Primitive data was found in the stream
 397      *          instead of objects.
 398      * @throws  IOException if I/O errors occurred while reading from the
 399      *          underlying stream
 400      * @see #ObjectInputStream()
 401      * @see #readObject()
 402      * @since 1.2
 403      */
 404     protected Object readObjectOverride()
 405         throws IOException, ClassNotFoundException
 406     {
 407         return null;
 408     }
 409 
 410     /**
 411      * Reads an "unshared" object from the ObjectInputStream.  This method is
 412      * identical to readObject, except that it prevents subsequent calls to
 413      * readObject and readUnshared from returning additional references to the
 414      * deserialized instance obtained via this call.  Specifically:
 415      * <ul>
 416      *   <li>If readUnshared is called to deserialize a back-reference (the
 417      *       stream representation of an object which has been written
 418      *       previously to the stream), an ObjectStreamException will be
 419      *       thrown.
 420      *
 421      *   <li>If readUnshared returns successfully, then any subsequent attempts
 422      *       to deserialize back-references to the stream handle deserialized
 423      *       by readUnshared will cause an ObjectStreamException to be thrown.
 424      * </ul>
 425      * Deserializing an object via readUnshared invalidates the stream handle
 426      * associated with the returned object.  Note that this in itself does not
 427      * always guarantee that the reference returned by readUnshared is unique;
 428      * the deserialized object may define a readResolve method which returns an
 429      * object visible to other parties, or readUnshared may return a Class
 430      * object or enum constant obtainable elsewhere in the stream or through
 431      * external means. If the deserialized object defines a readResolve method
 432      * and the invocation of that method returns an array, then readUnshared
 433      * returns a shallow clone of that array; this guarantees that the returned
 434      * array object is unique and cannot be obtained a second time from an
 435      * invocation of readObject or readUnshared on the ObjectInputStream,
 436      * even if the underlying data stream has been manipulated.
 437      *
 438      * <p>ObjectInputStream subclasses which override this method can only be
 439      * constructed in security contexts possessing the
 440      * "enableSubclassImplementation" SerializablePermission; any attempt to
 441      * instantiate such a subclass without this permission will cause a
 442      * SecurityException to be thrown.
 443      *
 444      * @return  reference to deserialized object
 445      * @throws  ClassNotFoundException if class of an object to deserialize
 446      *          cannot be found
 447      * @throws  StreamCorruptedException if control information in the stream
 448      *          is inconsistent
 449      * @throws  ObjectStreamException if object to deserialize has already
 450      *          appeared in stream
 451      * @throws  OptionalDataException if primitive data is next in stream
 452      * @throws  IOException if an I/O error occurs during deserialization
 453      * @since   1.4
 454      */
 455     public Object readUnshared() throws IOException, ClassNotFoundException {
 456         // if nested read, passHandle contains handle of enclosing object
 457         int outerHandle = passHandle;
 458         try {
 459             Object obj = readObject0(true);
 460             handles.markDependency(outerHandle, passHandle);
 461             ClassNotFoundException ex = handles.lookupException(passHandle);
 462             if (ex != null) {
 463                 throw ex;
 464             }
 465             if (depth == 0) {
 466                 vlist.doCallbacks();
 467                 freeze();
 468             }
 469             return obj;
 470         } finally {
 471             passHandle = outerHandle;
 472             if (closed && depth == 0) {
 473                 clear();
 474             }
 475         }
 476     }
 477 
 478     /**
 479      * Read the non-static and non-transient fields of the current class from
 480      * this stream.  This may only be called from the readObject method of the
 481      * class being deserialized. It will throw the NotActiveException if it is
 482      * called otherwise.
 483      *
 484      * @throws  ClassNotFoundException if the class of a serialized object
 485      *          could not be found.
 486      * @throws  IOException if an I/O error occurs.
 487      * @throws  NotActiveException if the stream is not currently reading
 488      *          objects.
 489      */
 490     public void defaultReadObject()
 491         throws IOException, ClassNotFoundException
 492     {
 493         SerialCallbackContext ctx = curContext;
 494         if (ctx == null) {
 495             throw new NotActiveException("not in call to readObject");
 496         }
 497         Object curObj = ctx.getObj();
 498         ObjectStreamClass curDesc = ctx.getDesc();
 499         bin.setBlockDataMode(false);
 500         FieldValues vals = defaultReadFields(curObj, curDesc);
 501         if (curObj != null) {
 502             defaultCheckFieldValues(curObj, curDesc, vals);
 503             defaultSetFieldValues(curObj, curDesc, vals);
 504         }
 505         bin.setBlockDataMode(true);
 506         if (!curDesc.hasWriteObjectData()) {
 507             /*
 508              * Fix for 4360508: since stream does not contain terminating
 509              * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
 510              * knows to simulate end-of-custom-data behavior.
 511              */
 512             defaultDataEnd = true;
 513         }
 514         ClassNotFoundException ex = handles.lookupException(passHandle);
 515         if (ex != null) {
 516             throw ex;
 517         }
 518     }
 519 
 520     /**
 521      * Reads the persistent fields from the stream and makes them available by
 522      * name.
 523      *
 524      * @return  the <code>GetField</code> object representing the persistent
 525      *          fields of the object being deserialized
 526      * @throws  ClassNotFoundException if the class of a serialized object
 527      *          could not be found.
 528      * @throws  IOException if an I/O error occurs.
 529      * @throws  NotActiveException if the stream is not currently reading
 530      *          objects.
 531      * @since 1.2
 532      */
 533     public ObjectInputStream.GetField readFields()
 534         throws IOException, ClassNotFoundException
 535     {
 536         SerialCallbackContext ctx = curContext;
 537         if (ctx == null) {
 538             throw new NotActiveException("not in call to readObject");
 539         }
 540         ctx.checkAndSetUsed();
 541         ObjectStreamClass curDesc = ctx.getDesc();
 542         bin.setBlockDataMode(false);
 543         GetFieldImpl getField = new GetFieldImpl(curDesc);
 544         getField.readFields();
 545         bin.setBlockDataMode(true);
 546         if (!curDesc.hasWriteObjectData()) {
 547             /*
 548              * Fix for 4360508: since stream does not contain terminating
 549              * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
 550              * knows to simulate end-of-custom-data behavior.
 551              */
 552             defaultDataEnd = true;
 553         }
 554 
 555         return getField;
 556     }
 557 
 558     /**
 559      * Register an object to be validated before the graph is returned.  While
 560      * similar to resolveObject these validations are called after the entire
 561      * graph has been reconstituted.  Typically, a readObject method will
 562      * register the object with the stream so that when all of the objects are
 563      * restored a final set of validations can be performed.
 564      *
 565      * @param   obj the object to receive the validation callback.
 566      * @param   prio controls the order of callbacks;zero is a good default.
 567      *          Use higher numbers to be called back earlier, lower numbers for
 568      *          later callbacks. Within a priority, callbacks are processed in
 569      *          no particular order.
 570      * @throws  NotActiveException The stream is not currently reading objects
 571      *          so it is invalid to register a callback.
 572      * @throws  InvalidObjectException The validation object is null.
 573      */
 574     public void registerValidation(ObjectInputValidation obj, int prio)
 575         throws NotActiveException, InvalidObjectException
 576     {
 577         if (depth == 0) {
 578             throw new NotActiveException("stream inactive");
 579         }
 580         vlist.register(obj, prio);
 581     }
 582 
 583     /**
 584      * Load the local class equivalent of the specified stream class
 585      * description.  Subclasses may implement this method to allow classes to
 586      * be fetched from an alternate source.
 587      *
 588      * <p>The corresponding method in <code>ObjectOutputStream</code> is
 589      * <code>annotateClass</code>.  This method will be invoked only once for
 590      * each unique class in the stream.  This method can be implemented by
 591      * subclasses to use an alternate loading mechanism but must return a
 592      * <code>Class</code> object. Once returned, if the class is not an array
 593      * class, its serialVersionUID is compared to the serialVersionUID of the
 594      * serialized class, and if there is a mismatch, the deserialization fails
 595      * and an {@link InvalidClassException} is thrown.
 596      *
 597      * <p>The default implementation of this method in
 598      * <code>ObjectInputStream</code> returns the result of calling
 599      * <pre>
 600      *     Class.forName(desc.getName(), false, loader)
 601      * </pre>
 602      * where <code>loader</code> is determined as follows: if there is a
 603      * method on the current thread's stack whose declaring class was
 604      * defined by a user-defined class loader (and was not a generated to
 605      * implement reflective invocations), then <code>loader</code> is class
 606      * loader corresponding to the closest such method to the currently
 607      * executing frame; otherwise, <code>loader</code> is
 608      * <code>null</code>. If this call results in a
 609      * <code>ClassNotFoundException</code> and the name of the passed
 610      * <code>ObjectStreamClass</code> instance is the Java language keyword
 611      * for a primitive type or void, then the <code>Class</code> object
 612      * representing that primitive type or void will be returned
 613      * (e.g., an <code>ObjectStreamClass</code> with the name
 614      * <code>"int"</code> will be resolved to <code>Integer.TYPE</code>).
 615      * Otherwise, the <code>ClassNotFoundException</code> will be thrown to
 616      * the caller of this method.
 617      *
 618      * @param   desc an instance of class <code>ObjectStreamClass</code>
 619      * @return  a <code>Class</code> object corresponding to <code>desc</code>
 620      * @throws  IOException any of the usual Input/Output exceptions.
 621      * @throws  ClassNotFoundException if class of a serialized object cannot
 622      *          be found.
 623      */
 624     protected Class<?> resolveClass(ObjectStreamClass desc)
 625         throws IOException, ClassNotFoundException
 626     {
 627         String name = desc.getName();
 628         try {
 629             return Class.forName(name, false, latestUserDefinedLoader());
 630         } catch (ClassNotFoundException ex) {
 631             Class<?> cl = primClasses.get(name);
 632             if (cl != null) {
 633                 return cl;
 634             } else {
 635                 throw ex;
 636             }
 637         }
 638     }
 639 
 640     /**
 641      * Returns a proxy class that implements the interfaces named in a proxy
 642      * class descriptor; subclasses may implement this method to read custom
 643      * data from the stream along with the descriptors for dynamic proxy
 644      * classes, allowing them to use an alternate loading mechanism for the
 645      * interfaces and the proxy class.
 646      *
 647      * <p>This method is called exactly once for each unique proxy class
 648      * descriptor in the stream.
 649      *
 650      * <p>The corresponding method in <code>ObjectOutputStream</code> is
 651      * <code>annotateProxyClass</code>.  For a given subclass of
 652      * <code>ObjectInputStream</code> that overrides this method, the
 653      * <code>annotateProxyClass</code> method in the corresponding subclass of
 654      * <code>ObjectOutputStream</code> must write any data or objects read by
 655      * this method.
 656      *
 657      * <p>The default implementation of this method in
 658      * <code>ObjectInputStream</code> returns the result of calling
 659      * <code>Proxy.getProxyClass</code> with the list of <code>Class</code>
 660      * objects for the interfaces that are named in the <code>interfaces</code>
 661      * parameter.  The <code>Class</code> object for each interface name
 662      * <code>i</code> is the value returned by calling
 663      * <pre>
 664      *     Class.forName(i, false, loader)
 665      * </pre>
 666      * where <code>loader</code> is that of the first non-<code>null</code>
 667      * class loader up the execution stack, or <code>null</code> if no
 668      * non-<code>null</code> class loaders are on the stack (the same class
 669      * loader choice used by the <code>resolveClass</code> method).  Unless any
 670      * of the resolved interfaces are non-public, this same value of
 671      * <code>loader</code> is also the class loader passed to
 672      * <code>Proxy.getProxyClass</code>; if non-public interfaces are present,
 673      * their class loader is passed instead (if more than one non-public
 674      * interface class loader is encountered, an
 675      * <code>IllegalAccessError</code> is thrown).
 676      * If <code>Proxy.getProxyClass</code> throws an
 677      * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code>
 678      * will throw a <code>ClassNotFoundException</code> containing the
 679      * <code>IllegalArgumentException</code>.
 680      *
 681      * @param interfaces the list of interface names that were
 682      *                deserialized in the proxy class descriptor
 683      * @return  a proxy class for the specified interfaces
 684      * @throws        IOException any exception thrown by the underlying
 685      *                <code>InputStream</code>
 686      * @throws        ClassNotFoundException if the proxy class or any of the
 687      *                named interfaces could not be found
 688      * @see ObjectOutputStream#annotateProxyClass(Class)
 689      * @since 1.3
 690      */
 691     protected Class<?> resolveProxyClass(String[] interfaces)
 692         throws IOException, ClassNotFoundException
 693     {
 694         ClassLoader latestLoader = latestUserDefinedLoader();
 695         ClassLoader nonPublicLoader = null;
 696         boolean hasNonPublicInterface = false;
 697 
 698         // define proxy in class loader of non-public interface(s), if any
 699         Class<?>[] classObjs = new Class<?>[interfaces.length];
 700         for (int i = 0; i < interfaces.length; i++) {
 701             Class<?> cl = Class.forName(interfaces[i], false, latestLoader);
 702             if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
 703                 if (hasNonPublicInterface) {
 704                     if (nonPublicLoader != cl.getClassLoader()) {
 705                         throw new IllegalAccessError(
 706                             "conflicting non-public interface class loaders");
 707                     }
 708                 } else {
 709                     nonPublicLoader = cl.getClassLoader();
 710                     hasNonPublicInterface = true;
 711                 }
 712             }
 713             classObjs[i] = cl;
 714         }
 715         try {
 716             return Proxy.getProxyClass(
 717                 hasNonPublicInterface ? nonPublicLoader : latestLoader,
 718                 classObjs);
 719         } catch (IllegalArgumentException e) {
 720             throw new ClassNotFoundException(null, e);
 721         }
 722     }
 723 
 724     /**
 725      * This method will allow trusted subclasses of ObjectInputStream to
 726      * substitute one object for another during deserialization. Replacing
 727      * objects is disabled until enableResolveObject is called. The
 728      * enableResolveObject method checks that the stream requesting to resolve
 729      * object can be trusted. Every reference to serializable objects is passed
 730      * to resolveObject.  To insure that the private state of objects is not
 731      * unintentionally exposed only trusted streams may use resolveObject.
 732      *
 733      * <p>This method is called after an object has been read but before it is
 734      * returned from readObject.  The default resolveObject method just returns
 735      * the same object.
 736      *
 737      * <p>When a subclass is replacing objects it must insure that the
 738      * substituted object is compatible with every field where the reference
 739      * will be stored.  Objects whose type is not a subclass of the type of the
 740      * field or array element abort the serialization by raising an exception
 741      * and the object is not be stored.
 742      *
 743      * <p>This method is called only once when each object is first
 744      * encountered.  All subsequent references to the object will be redirected
 745      * to the new object.
 746      *
 747      * @param   obj object to be substituted
 748      * @return  the substituted object
 749      * @throws  IOException Any of the usual Input/Output exceptions.
 750      */
 751     protected Object resolveObject(Object obj) throws IOException {
 752         return obj;
 753     }
 754 
 755     /**
 756      * Enable the stream to allow objects read from the stream to be replaced.
 757      * When enabled, the resolveObject method is called for every object being
 758      * deserialized.
 759      *
 760      * <p>If <i>enable</i> is true, and there is a security manager installed,
 761      * this method first calls the security manager's
 762      * <code>checkPermission</code> method with the
 763      * <code>SerializablePermission("enableSubstitution")</code> permission to
 764      * ensure it's ok to enable the stream to allow objects read from the
 765      * stream to be replaced.
 766      *
 767      * @param   enable true for enabling use of <code>resolveObject</code> for
 768      *          every object being deserialized
 769      * @return  the previous setting before this method was invoked
 770      * @throws  SecurityException if a security manager exists and its
 771      *          <code>checkPermission</code> method denies enabling the stream
 772      *          to allow objects read from the stream to be replaced.
 773      * @see SecurityManager#checkPermission
 774      * @see java.io.SerializablePermission
 775      */
 776     protected boolean enableResolveObject(boolean enable)
 777         throws SecurityException
 778     {
 779         if (enable == enableResolve) {
 780             return enable;
 781         }
 782         if (enable) {
 783             SecurityManager sm = System.getSecurityManager();
 784             if (sm != null) {
 785                 sm.checkPermission(SUBSTITUTION_PERMISSION);
 786             }
 787         }
 788         enableResolve = enable;
 789         return !enableResolve;
 790     }
 791 
 792     /**
 793      * The readStreamHeader method is provided to allow subclasses to read and
 794      * verify their own stream headers. It reads and verifies the magic number
 795      * and version number.
 796      *
 797      * @throws  IOException if there are I/O errors while reading from the
 798      *          underlying <code>InputStream</code>
 799      * @throws  StreamCorruptedException if control information in the stream
 800      *          is inconsistent
 801      */
 802     protected void readStreamHeader()
 803         throws IOException, StreamCorruptedException
 804     {
 805         short s0 = bin.readShort();
 806         short s1 = bin.readShort();
 807         if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
 808             throw new StreamCorruptedException(
 809                 String.format("invalid stream header: %04X%04X", s0, s1));
 810         }
 811     }
 812 
 813     /**
 814      * Read a class descriptor from the serialization stream.  This method is
 815      * called when the ObjectInputStream expects a class descriptor as the next
 816      * item in the serialization stream.  Subclasses of ObjectInputStream may
 817      * override this method to read in class descriptors that have been written
 818      * in non-standard formats (by subclasses of ObjectOutputStream which have
 819      * overridden the <code>writeClassDescriptor</code> method).  By default,
 820      * this method reads class descriptors according to the format defined in
 821      * the Object Serialization specification.
 822      *
 823      * @return  the class descriptor read
 824      * @throws  IOException If an I/O error has occurred.
 825      * @throws  ClassNotFoundException If the Class of a serialized object used
 826      *          in the class descriptor representation cannot be found
 827      * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
 828      * @since 1.3
 829      */
 830     protected ObjectStreamClass readClassDescriptor()
 831         throws IOException, ClassNotFoundException
 832     {
 833         ObjectStreamClass desc = new ObjectStreamClass();
 834         desc.readNonProxy(this);
 835         return desc;
 836     }
 837 
 838     /**
 839      * Reads a byte of data. This method will block if no input is available.
 840      *
 841      * @return  the byte read, or -1 if the end of the stream is reached.
 842      * @throws  IOException If an I/O error has occurred.
 843      */
 844     public int read() throws IOException {
 845         return bin.read();
 846     }
 847 
 848     /**
 849      * Reads into an array of bytes.  This method will block until some input
 850      * is available. Consider using java.io.DataInputStream.readFully to read
 851      * exactly 'length' bytes.
 852      *
 853      * @param   buf the buffer into which the data is read
 854      * @param   off the start offset of the data
 855      * @param   len the maximum number of bytes read
 856      * @return  the actual number of bytes read, -1 is returned when the end of
 857      *          the stream is reached.
 858      * @throws  IOException If an I/O error has occurred.
 859      * @see java.io.DataInputStream#readFully(byte[],int,int)
 860      */
 861     public int read(byte[] buf, int off, int len) throws IOException {
 862         if (buf == null) {
 863             throw new NullPointerException();
 864         }
 865         int endoff = off + len;
 866         if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
 867             throw new IndexOutOfBoundsException();
 868         }
 869         return bin.read(buf, off, len, false);
 870     }
 871 
 872     /**
 873      * Returns the number of bytes that can be read without blocking.
 874      *
 875      * @return  the number of available bytes.
 876      * @throws  IOException if there are I/O errors while reading from the
 877      *          underlying <code>InputStream</code>
 878      */
 879     public int available() throws IOException {
 880         return bin.available();
 881     }
 882 
 883     /**
 884      * Closes the input stream. Must be called to release any resources
 885      * associated with the stream.
 886      *
 887      * @throws  IOException If an I/O error has occurred.
 888      */
 889     public void close() throws IOException {
 890         /*
 891          * Even if stream already closed, propagate redundant close to
 892          * underlying stream to stay consistent with previous implementations.
 893          */
 894         closed = true;
 895         if (depth == 0) {
 896             clear();
 897         }
 898         bin.close();
 899     }
 900 
 901     /**
 902      * Reads in a boolean.
 903      *
 904      * @return  the boolean read.
 905      * @throws  EOFException If end of file is reached.
 906      * @throws  IOException If other I/O error has occurred.
 907      */
 908     public boolean readBoolean() throws IOException {
 909         return bin.readBoolean();
 910     }
 911 
 912     /**
 913      * Reads an 8 bit byte.
 914      *
 915      * @return  the 8 bit byte read.
 916      * @throws  EOFException If end of file is reached.
 917      * @throws  IOException If other I/O error has occurred.
 918      */
 919     public byte readByte() throws IOException  {
 920         return bin.readByte();
 921     }
 922 
 923     /**
 924      * Reads an unsigned 8 bit byte.
 925      *
 926      * @return  the 8 bit byte read.
 927      * @throws  EOFException If end of file is reached.
 928      * @throws  IOException If other I/O error has occurred.
 929      */
 930     public int readUnsignedByte()  throws IOException {
 931         return bin.readUnsignedByte();
 932     }
 933 
 934     /**
 935      * Reads a 16 bit char.
 936      *
 937      * @return  the 16 bit char read.
 938      * @throws  EOFException If end of file is reached.
 939      * @throws  IOException If other I/O error has occurred.
 940      */
 941     public char readChar()  throws IOException {
 942         return bin.readChar();
 943     }
 944 
 945     /**
 946      * Reads a 16 bit short.
 947      *
 948      * @return  the 16 bit short read.
 949      * @throws  EOFException If end of file is reached.
 950      * @throws  IOException If other I/O error has occurred.
 951      */
 952     public short readShort()  throws IOException {
 953         return bin.readShort();
 954     }
 955 
 956     /**
 957      * Reads an unsigned 16 bit short.
 958      *
 959      * @return  the 16 bit short read.
 960      * @throws  EOFException If end of file is reached.
 961      * @throws  IOException If other I/O error has occurred.
 962      */
 963     public int readUnsignedShort() throws IOException {
 964         return bin.readUnsignedShort();
 965     }
 966 
 967     /**
 968      * Reads a 32 bit int.
 969      *
 970      * @return  the 32 bit integer read.
 971      * @throws  EOFException If end of file is reached.
 972      * @throws  IOException If other I/O error has occurred.
 973      */
 974     public int readInt()  throws IOException {
 975         return bin.readInt();
 976     }
 977 
 978     /**
 979      * Reads a 64 bit long.
 980      *
 981      * @return  the read 64 bit long.
 982      * @throws  EOFException If end of file is reached.
 983      * @throws  IOException If other I/O error has occurred.
 984      */
 985     public long readLong()  throws IOException {
 986         return bin.readLong();
 987     }
 988 
 989     /**
 990      * Reads a 32 bit float.
 991      *
 992      * @return  the 32 bit float read.
 993      * @throws  EOFException If end of file is reached.
 994      * @throws  IOException If other I/O error has occurred.
 995      */
 996     public float readFloat() throws IOException {
 997         return bin.readFloat();
 998     }
 999 
1000     /**
1001      * Reads a 64 bit double.
1002      *
1003      * @return  the 64 bit double read.
1004      * @throws  EOFException If end of file is reached.
1005      * @throws  IOException If other I/O error has occurred.
1006      */
1007     public double readDouble() throws IOException {
1008         return bin.readDouble();
1009     }
1010 
1011     /**
1012      * Reads bytes, blocking until all bytes are read.
1013      *
1014      * @param   buf the buffer into which the data is read
1015      * @throws  EOFException If end of file is reached.
1016      * @throws  IOException If other I/O error has occurred.
1017      */
1018     public void readFully(byte[] buf) throws IOException {
1019         bin.readFully(buf, 0, buf.length, false);
1020     }
1021 
1022     /**
1023      * Reads bytes, blocking until all bytes are read.
1024      *
1025      * @param   buf the buffer into which the data is read
1026      * @param   off the start offset of the data
1027      * @param   len the maximum number of bytes to read
1028      * @throws  EOFException If end of file is reached.
1029      * @throws  IOException If other I/O error has occurred.
1030      */
1031     public void readFully(byte[] buf, int off, int len) throws IOException {
1032         int endoff = off + len;
1033         if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
1034             throw new IndexOutOfBoundsException();
1035         }
1036         bin.readFully(buf, off, len, false);
1037     }
1038 
1039     /**
1040      * Skips bytes.
1041      *
1042      * @param   len the number of bytes to be skipped
1043      * @return  the actual number of bytes skipped.
1044      * @throws  IOException If an I/O error has occurred.
1045      */
1046     public int skipBytes(int len) throws IOException {
1047         return bin.skipBytes(len);
1048     }
1049 
1050     /**
1051      * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
1052      *
1053      * @return  a String copy of the line.
1054      * @throws  IOException if there are I/O errors while reading from the
1055      *          underlying <code>InputStream</code>
1056      * @deprecated This method does not properly convert bytes to characters.
1057      *          see DataInputStream for the details and alternatives.
1058      */
1059     @Deprecated
1060     public String readLine() throws IOException {
1061         return bin.readLine();
1062     }
1063 
1064     /**
1065      * Reads a String in
1066      * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
1067      * format.
1068      *
1069      * @return  the String.
1070      * @throws  IOException if there are I/O errors while reading from the
1071      *          underlying <code>InputStream</code>
1072      * @throws  UTFDataFormatException if read bytes do not represent a valid
1073      *          modified UTF-8 encoding of a string
1074      */
1075     public String readUTF() throws IOException {
1076         return bin.readUTF();
1077     }
1078 
1079     /**
1080      * Provide access to the persistent fields read from the input stream.
1081      */
1082     public abstract static class GetField {
1083 
1084         /**
1085          * Get the ObjectStreamClass that describes the fields in the stream.
1086          *
1087          * @return  the descriptor class that describes the serializable fields
1088          */
1089         public abstract ObjectStreamClass getObjectStreamClass();
1090 
1091         /**
1092          * Return true if the named field is defaulted and has no value in this
1093          * stream.
1094          *
1095          * @param  name the name of the field
1096          * @return true, if and only if the named field is defaulted
1097          * @throws IOException if there are I/O errors while reading from
1098          *         the underlying <code>InputStream</code>
1099          * @throws IllegalArgumentException if <code>name</code> does not
1100          *         correspond to a serializable field
1101          */
1102         public abstract boolean defaulted(String name) throws IOException;
1103 
1104         /**
1105          * Get the value of the named boolean field from the persistent field.
1106          *
1107          * @param  name the name of the field
1108          * @param  val the default value to use if <code>name</code> does not
1109          *         have a value
1110          * @return the value of the named <code>boolean</code> field
1111          * @throws IOException if there are I/O errors while reading from the
1112          *         underlying <code>InputStream</code>
1113          * @throws IllegalArgumentException if type of <code>name</code> is
1114          *         not serializable or if the field type is incorrect
1115          */
1116         public abstract boolean get(String name, boolean val)
1117             throws IOException;
1118 
1119         /**
1120          * Get the value of the named byte field from the persistent field.
1121          *
1122          * @param  name the name of the field
1123          * @param  val the default value to use if <code>name</code> does not
1124          *         have a value
1125          * @return the value of the named <code>byte</code> field
1126          * @throws IOException if there are I/O errors while reading from the
1127          *         underlying <code>InputStream</code>
1128          * @throws IllegalArgumentException if type of <code>name</code> is
1129          *         not serializable or if the field type is incorrect
1130          */
1131         public abstract byte get(String name, byte val) throws IOException;
1132 
1133         /**
1134          * Get the value of the named char field from the persistent field.
1135          *
1136          * @param  name the name of the field
1137          * @param  val the default value to use if <code>name</code> does not
1138          *         have a value
1139          * @return the value of the named <code>char</code> field
1140          * @throws IOException if there are I/O errors while reading from the
1141          *         underlying <code>InputStream</code>
1142          * @throws IllegalArgumentException if type of <code>name</code> is
1143          *         not serializable or if the field type is incorrect
1144          */
1145         public abstract char get(String name, char val) throws IOException;
1146 
1147         /**
1148          * Get the value of the named short field from the persistent field.
1149          *
1150          * @param  name the name of the field
1151          * @param  val the default value to use if <code>name</code> does not
1152          *         have a value
1153          * @return the value of the named <code>short</code> field
1154          * @throws IOException if there are I/O errors while reading from the
1155          *         underlying <code>InputStream</code>
1156          * @throws IllegalArgumentException if type of <code>name</code> is
1157          *         not serializable or if the field type is incorrect
1158          */
1159         public abstract short get(String name, short val) throws IOException;
1160 
1161         /**
1162          * Get the value of the named int field from the persistent field.
1163          *
1164          * @param  name the name of the field
1165          * @param  val the default value to use if <code>name</code> does not
1166          *         have a value
1167          * @return the value of the named <code>int</code> field
1168          * @throws IOException if there are I/O errors while reading from the
1169          *         underlying <code>InputStream</code>
1170          * @throws IllegalArgumentException if type of <code>name</code> is
1171          *         not serializable or if the field type is incorrect
1172          */
1173         public abstract int get(String name, int val) throws IOException;
1174 
1175         /**
1176          * Get the value of the named long field from the persistent field.
1177          *
1178          * @param  name the name of the field
1179          * @param  val the default value to use if <code>name</code> does not
1180          *         have a value
1181          * @return the value of the named <code>long</code> field
1182          * @throws IOException if there are I/O errors while reading from the
1183          *         underlying <code>InputStream</code>
1184          * @throws IllegalArgumentException if type of <code>name</code> is
1185          *         not serializable or if the field type is incorrect
1186          */
1187         public abstract long get(String name, long val) throws IOException;
1188 
1189         /**
1190          * Get the value of the named float field from the persistent field.
1191          *
1192          * @param  name the name of the field
1193          * @param  val the default value to use if <code>name</code> does not
1194          *         have a value
1195          * @return the value of the named <code>float</code> field
1196          * @throws IOException if there are I/O errors while reading from the
1197          *         underlying <code>InputStream</code>
1198          * @throws IllegalArgumentException if type of <code>name</code> is
1199          *         not serializable or if the field type is incorrect
1200          */
1201         public abstract float get(String name, float val) throws IOException;
1202 
1203         /**
1204          * Get the value of the named double field from the persistent field.
1205          *
1206          * @param  name the name of the field
1207          * @param  val the default value to use if <code>name</code> does not
1208          *         have a value
1209          * @return the value of the named <code>double</code> field
1210          * @throws IOException if there are I/O errors while reading from the
1211          *         underlying <code>InputStream</code>
1212          * @throws IllegalArgumentException if type of <code>name</code> is
1213          *         not serializable or if the field type is incorrect
1214          */
1215         public abstract double get(String name, double val) throws IOException;
1216 
1217         /**
1218          * Get the value of the named Object field from the persistent field.
1219          *
1220          * @param  name the name of the field
1221          * @param  val the default value to use if <code>name</code> does not
1222          *         have a value
1223          * @return the value of the named <code>Object</code> field
1224          * @throws IOException if there are I/O errors while reading from the
1225          *         underlying <code>InputStream</code>
1226          * @throws IllegalArgumentException if type of <code>name</code> is
1227          *         not serializable or if the field type is incorrect
1228          */
1229         public abstract Object get(String name, Object val) throws IOException;
1230     }
1231 
1232     /**
1233      * Verifies that this (possibly subclass) instance can be constructed
1234      * without violating security constraints: the subclass must not override
1235      * security-sensitive non-final methods, or else the
1236      * "enableSubclassImplementation" SerializablePermission is checked.
1237      */
1238     private void verifySubclass() {
1239         Class<?> cl = getClass();
1240         if (cl == ObjectInputStream.class) {
1241             return;
1242         }
1243         SecurityManager sm = System.getSecurityManager();
1244         if (sm == null) {
1245             return;
1246         }
1247         processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
1248         WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
1249         Boolean result = Caches.subclassAudits.get(key);
1250         if (result == null) {
1251             result = Boolean.valueOf(auditSubclass(cl));
1252             Caches.subclassAudits.putIfAbsent(key, result);
1253         }
1254         if (result.booleanValue()) {
1255             return;
1256         }
1257         sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1258     }
1259 
1260     /**
1261      * Performs reflective checks on given subclass to verify that it doesn't
1262      * override security-sensitive non-final methods.  Returns true if subclass
1263      * is "safe", false otherwise.
1264      */
1265     private static boolean auditSubclass(final Class<?> subcl) {
1266         Boolean result = AccessController.doPrivileged(
1267             new PrivilegedAction<>() {
1268                 public Boolean run() {
1269                     for (Class<?> cl = subcl;
1270                          cl != ObjectInputStream.class;
1271                          cl = cl.getSuperclass())
1272                     {
1273                         try {
1274                             cl.getDeclaredMethod(
1275                                 "readUnshared", (Class[]) null);
1276                             return Boolean.FALSE;
1277                         } catch (NoSuchMethodException ex) {
1278                         }
1279                         try {
1280                             cl.getDeclaredMethod("readFields", (Class[]) null);
1281                             return Boolean.FALSE;
1282                         } catch (NoSuchMethodException ex) {
1283                         }
1284                     }
1285                     return Boolean.TRUE;
1286                 }
1287             }
1288         );
1289         return result.booleanValue();
1290     }
1291 
1292     /**
1293      * Clears internal data structures.
1294      */
1295     private void clear() {
1296         handles.clear();
1297         vlist.clear();
1298     }
1299 
1300     /**
1301      * Underlying readObject implementation.
1302      */
1303     private Object readObject0(boolean unshared) throws IOException {
1304         boolean oldMode = bin.getBlockDataMode();
1305         if (oldMode) {
1306             int remain = bin.currentBlockRemaining();
1307             if (remain > 0) {
1308                 throw new OptionalDataException(remain);
1309             } else if (defaultDataEnd) {
1310                 /*
1311                  * Fix for 4360508: stream is currently at the end of a field
1312                  * value block written via default serialization; since there
1313                  * is no terminating TC_ENDBLOCKDATA tag, simulate
1314                  * end-of-custom-data behavior explicitly.
1315                  */
1316                 throw new OptionalDataException(true);
1317             }
1318             bin.setBlockDataMode(false);
1319         }
1320 
1321         byte tc;
1322         while ((tc = bin.peekByte()) == TC_RESET) {
1323             bin.readByte();
1324             handleReset();
1325         }
1326 
1327         depth++;
1328         try {
1329             switch (tc) {
1330                 case TC_NULL:
1331                     return readNull();
1332 
1333                 case TC_REFERENCE:
1334                     return readHandle(unshared);
1335 
1336                 case TC_CLASS:
1337                     return readClass(unshared);
1338 
1339                 case TC_CLASSDESC:
1340                 case TC_PROXYCLASSDESC:
1341                     return readClassDesc(unshared);
1342 
1343                 case TC_STRING:
1344                 case TC_LONGSTRING:
1345                     return checkResolve(readString(unshared));
1346 
1347                 case TC_ARRAY:
1348                     return checkResolve(readArray(unshared));
1349 
1350                 case TC_ENUM:
1351                     return checkResolve(readEnum(unshared));
1352 
1353                 case TC_OBJECT:
1354                     return checkResolve(readOrdinaryObject(unshared));
1355 
1356                 case TC_EXCEPTION:
1357                     IOException ex = readFatalException();
1358                     throw new WriteAbortedException("writing aborted", ex);
1359 
1360                 case TC_BLOCKDATA:
1361                 case TC_BLOCKDATALONG:
1362                     if (oldMode) {
1363                         bin.setBlockDataMode(true);
1364                         bin.peek();             // force header read
1365                         throw new OptionalDataException(
1366                             bin.currentBlockRemaining());
1367                     } else {
1368                         throw new StreamCorruptedException(
1369                             "unexpected block data");
1370                     }
1371 
1372                 case TC_ENDBLOCKDATA:
1373                     if (oldMode) {
1374                         throw new OptionalDataException(true);
1375                     } else {
1376                         throw new StreamCorruptedException(
1377                             "unexpected end of block data");
1378                     }
1379 
1380                 default:
1381                     throw new StreamCorruptedException(
1382                         String.format("invalid type code: %02X", tc));
1383             }
1384         } finally {
1385             depth--;
1386             bin.setBlockDataMode(oldMode);
1387         }
1388     }
1389 
1390     /**
1391      * If resolveObject has been enabled and given object does not have an
1392      * exception associated with it, calls resolveObject to determine
1393      * replacement for object, and updates handle table accordingly.  Returns
1394      * replacement object, or echoes provided object if no replacement
1395      * occurred.  Expects that passHandle is set to given object's handle prior
1396      * to calling this method.
1397      */
1398     private Object checkResolve(Object obj) throws IOException {
1399         if (!enableResolve || handles.lookupException(passHandle) != null) {
1400             return obj;
1401         }
1402         Object rep = resolveObject(obj);
1403         if (rep != obj) {
1404             handles.setObject(passHandle, rep);
1405         }
1406         return rep;
1407     }
1408 
1409     /**
1410      * Reads string without allowing it to be replaced in stream.  Called from
1411      * within ObjectStreamClass.read().
1412      */
1413     String readTypeString() throws IOException {
1414         int oldHandle = passHandle;
1415         try {
1416             byte tc = bin.peekByte();
1417             switch (tc) {
1418                 case TC_NULL:
1419                     return (String) readNull();
1420 
1421                 case TC_REFERENCE:
1422                     return (String) readHandle(false);
1423 
1424                 case TC_STRING:
1425                 case TC_LONGSTRING:
1426                     return readString(false);
1427 
1428                 default:
1429                     throw new StreamCorruptedException(
1430                         String.format("invalid type code: %02X", tc));
1431             }
1432         } finally {
1433             passHandle = oldHandle;
1434         }
1435     }
1436 
1437     /**
1438      * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
1439      */
1440     private Object readNull() throws IOException {
1441         if (bin.readByte() != TC_NULL) {
1442             throw new InternalError();
1443         }
1444         passHandle = NULL_HANDLE;
1445         return null;
1446     }
1447 
1448     /**
1449      * Reads in object handle, sets passHandle to the read handle, and returns
1450      * object associated with the handle.
1451      */
1452     private Object readHandle(boolean unshared) throws IOException {
1453         if (bin.readByte() != TC_REFERENCE) {
1454             throw new InternalError();
1455         }
1456         passHandle = bin.readInt() - baseWireHandle;
1457         if (passHandle < 0 || passHandle >= handles.size()) {
1458             throw new StreamCorruptedException(
1459                 String.format("invalid handle value: %08X", passHandle +
1460                 baseWireHandle));
1461         }
1462         if (unshared) {
1463             // REMIND: what type of exception to throw here?
1464             throw new InvalidObjectException(
1465                 "cannot read back reference as unshared");
1466         }
1467 
1468         Object obj = handles.lookupObject(passHandle);
1469         if (obj == unsharedMarker) {
1470             // REMIND: what type of exception to throw here?
1471             throw new InvalidObjectException(
1472                 "cannot read back reference to unshared object");
1473         }
1474         return obj;
1475     }
1476 
1477     /**
1478      * Reads in and returns class object.  Sets passHandle to class object's
1479      * assigned handle.  Returns null if class is unresolvable (in which case a
1480      * ClassNotFoundException will be associated with the class' handle in the
1481      * handle table).
1482      */
1483     private Class<?> readClass(boolean unshared) throws IOException {
1484         if (bin.readByte() != TC_CLASS) {
1485             throw new InternalError();
1486         }
1487         ObjectStreamClass desc = readClassDesc(false);
1488         Class<?> cl = desc.forClass();
1489         passHandle = handles.assign(unshared ? unsharedMarker : cl);
1490 
1491         ClassNotFoundException resolveEx = desc.getResolveException();
1492         if (resolveEx != null) {
1493             handles.markException(passHandle, resolveEx);
1494         }
1495 
1496         handles.finish(passHandle);
1497         return cl;
1498     }
1499 
1500     /**
1501      * Reads in and returns (possibly null) class descriptor.  Sets passHandle
1502      * to class descriptor's assigned handle.  If class descriptor cannot be
1503      * resolved to a class in the local VM, a ClassNotFoundException is
1504      * associated with the class descriptor's handle.
1505      */
1506     private ObjectStreamClass readClassDesc(boolean unshared)
1507         throws IOException
1508     {
1509         byte tc = bin.peekByte();
1510         switch (tc) {
1511             case TC_NULL:
1512                 return (ObjectStreamClass) readNull();
1513 
1514             case TC_REFERENCE:
1515                 return (ObjectStreamClass) readHandle(unshared);
1516 
1517             case TC_PROXYCLASSDESC:
1518                 return readProxyDesc(unshared);
1519 
1520             case TC_CLASSDESC:
1521                 return readNonProxyDesc(unshared);
1522 
1523             default:
1524                 throw new StreamCorruptedException(
1525                     String.format("invalid type code: %02X", tc));
1526         }
1527     }
1528 
1529     private boolean isCustomSubclass() {
1530         // Return true if this class is a custom subclass of ObjectInputStream
1531         return getClass().getClassLoader()
1532                     != ObjectInputStream.class.getClassLoader();
1533     }
1534 
1535     /**
1536      * Reads in and returns class descriptor for a dynamic proxy class.  Sets
1537      * passHandle to proxy class descriptor's assigned handle.  If proxy class
1538      * descriptor cannot be resolved to a class in the local VM, a
1539      * ClassNotFoundException is associated with the descriptor's handle.
1540      */
1541     private ObjectStreamClass readProxyDesc(boolean unshared)
1542         throws IOException
1543     {
1544         if (bin.readByte() != TC_PROXYCLASSDESC) {
1545             throw new InternalError();
1546         }
1547 
1548         ObjectStreamClass desc = new ObjectStreamClass();
1549         int descHandle = handles.assign(unshared ? unsharedMarker : desc);
1550         passHandle = NULL_HANDLE;
1551 
1552         int numIfaces = bin.readInt();
1553         String[] ifaces = new String[numIfaces];
1554         for (int i = 0; i < numIfaces; i++) {
1555             ifaces[i] = bin.readUTF();
1556         }
1557 
1558         Class<?> cl = null;
1559         ClassNotFoundException resolveEx = null;
1560         bin.setBlockDataMode(true);
1561         try {
1562             if ((cl = resolveProxyClass(ifaces)) == null) {
1563                 resolveEx = new ClassNotFoundException("null class");
1564             } else if (!Proxy.isProxyClass(cl)) {
1565                 throw new InvalidClassException("Not a proxy");
1566             } else {
1567                 // ReflectUtil.checkProxyPackageAccess makes a test
1568                 // equivalent to isCustomSubclass so there's no need
1569                 // to condition this call to isCustomSubclass == true here.
1570                 ReflectUtil.checkProxyPackageAccess(
1571                         getClass().getClassLoader(),
1572                         cl.getInterfaces());
1573             }
1574         } catch (ClassNotFoundException ex) {
1575             resolveEx = ex;
1576         }
1577         skipCustomData();
1578 
1579         desc.initProxy(cl, resolveEx, readClassDesc(false));
1580 
1581         handles.finish(descHandle);
1582         passHandle = descHandle;
1583         return desc;
1584     }
1585 
1586     /**
1587      * Reads in and returns class descriptor for a class that is not a dynamic
1588      * proxy class.  Sets passHandle to class descriptor's assigned handle.  If
1589      * class descriptor cannot be resolved to a class in the local VM, a
1590      * ClassNotFoundException is associated with the descriptor's handle.
1591      */
1592     private ObjectStreamClass readNonProxyDesc(boolean unshared)
1593         throws IOException
1594     {
1595         if (bin.readByte() != TC_CLASSDESC) {
1596             throw new InternalError();
1597         }
1598 
1599         ObjectStreamClass desc = new ObjectStreamClass();
1600         int descHandle = handles.assign(unshared ? unsharedMarker : desc);
1601         passHandle = NULL_HANDLE;
1602 
1603         ObjectStreamClass readDesc;
1604         try {
1605             readDesc = readClassDescriptor();
1606         } catch (ClassNotFoundException ex) {
1607             throw (IOException) new InvalidClassException(
1608                 "failed to read class descriptor").initCause(ex);
1609         }
1610 
1611         Class<?> cl = null;
1612         ClassNotFoundException resolveEx = null;
1613         bin.setBlockDataMode(true);
1614         final boolean checksRequired = isCustomSubclass();
1615         try {
1616             if ((cl = resolveClass(readDesc)) == null) {
1617                 resolveEx = new ClassNotFoundException("null class");
1618             } else if (checksRequired) {
1619                 ReflectUtil.checkPackageAccess(cl);
1620             }
1621         } catch (ClassNotFoundException ex) {
1622             resolveEx = ex;
1623         }
1624         skipCustomData();
1625 
1626         desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
1627 
1628         handles.finish(descHandle);
1629         passHandle = descHandle;
1630         return desc;
1631     }
1632 
1633     /**
1634      * Reads in and returns new string.  Sets passHandle to new string's
1635      * assigned handle.
1636      */
1637     private String readString(boolean unshared) throws IOException {
1638         String str;
1639         byte tc = bin.readByte();
1640         switch (tc) {
1641             case TC_STRING:
1642                 str = bin.readUTF();
1643                 break;
1644 
1645             case TC_LONGSTRING:
1646                 str = bin.readLongUTF();
1647                 break;
1648 
1649             default:
1650                 throw new StreamCorruptedException(
1651                     String.format("invalid type code: %02X", tc));
1652         }
1653         passHandle = handles.assign(unshared ? unsharedMarker : str);
1654         handles.finish(passHandle);
1655         return str;
1656     }
1657 
1658     /**
1659      * Reads in and returns array object, or null if array class is
1660      * unresolvable.  Sets passHandle to array's assigned handle.
1661      */
1662     private Object readArray(boolean unshared) throws IOException {
1663         if (bin.readByte() != TC_ARRAY) {
1664             throw new InternalError();
1665         }
1666 
1667         ObjectStreamClass desc = readClassDesc(false);
1668         int len = bin.readInt();
1669 
1670         Object array = null;
1671         Class<?> cl, ccl = null;
1672         if ((cl = desc.forClass()) != null) {
1673             ccl = cl.getComponentType();
1674             array = Array.newInstance(ccl, len);
1675         }
1676 
1677         int arrayHandle = handles.assign(unshared ? unsharedMarker : array);
1678         ClassNotFoundException resolveEx = desc.getResolveException();
1679         if (resolveEx != null) {
1680             handles.markException(arrayHandle, resolveEx);
1681         }
1682 
1683         if (ccl == null) {
1684             for (int i = 0; i < len; i++) {
1685                 readObject0(false);
1686             }
1687         } else if (ccl.isPrimitive()) {
1688             if (ccl == Integer.TYPE) {
1689                 bin.readInts((int[]) array, 0, len);
1690             } else if (ccl == Byte.TYPE) {
1691                 bin.readFully((byte[]) array, 0, len, true);
1692             } else if (ccl == Long.TYPE) {
1693                 bin.readLongs((long[]) array, 0, len);
1694             } else if (ccl == Float.TYPE) {
1695                 bin.readFloats((float[]) array, 0, len);
1696             } else if (ccl == Double.TYPE) {
1697                 bin.readDoubles((double[]) array, 0, len);
1698             } else if (ccl == Short.TYPE) {
1699                 bin.readShorts((short[]) array, 0, len);
1700             } else if (ccl == Character.TYPE) {
1701                 bin.readChars((char[]) array, 0, len);
1702             } else if (ccl == Boolean.TYPE) {
1703                 bin.readBooleans((boolean[]) array, 0, len);
1704             } else {
1705                 throw new InternalError();
1706             }
1707         } else {
1708             Object[] oa = (Object[]) array;
1709             for (int i = 0; i < len; i++) {
1710                 oa[i] = readObject0(false);
1711                 handles.markDependency(arrayHandle, passHandle);
1712             }
1713         }
1714 
1715         handles.finish(arrayHandle);
1716         passHandle = arrayHandle;
1717         return array;
1718     }
1719 
1720     /**
1721      * Reads in and returns enum constant, or null if enum type is
1722      * unresolvable.  Sets passHandle to enum constant's assigned handle.
1723      */
1724     private Enum<?> readEnum(boolean unshared) throws IOException {
1725         if (bin.readByte() != TC_ENUM) {
1726             throw new InternalError();
1727         }
1728 
1729         ObjectStreamClass desc = readClassDesc(false);
1730         if (!desc.isEnum()) {
1731             throw new InvalidClassException("non-enum class: " + desc);
1732         }
1733 
1734         int enumHandle = handles.assign(unshared ? unsharedMarker : null);
1735         ClassNotFoundException resolveEx = desc.getResolveException();
1736         if (resolveEx != null) {
1737             handles.markException(enumHandle, resolveEx);
1738         }
1739 
1740         String name = readString(false);
1741         Enum<?> result = null;
1742         Class<?> cl = desc.forClass();
1743         if (cl != null) {
1744             try {
1745                 @SuppressWarnings("unchecked")
1746                 Enum<?> en = Enum.valueOf((Class)cl, name);
1747                 result = en;
1748             } catch (IllegalArgumentException ex) {
1749                 throw (IOException) new InvalidObjectException(
1750                     "enum constant " + name + " does not exist in " +
1751                     cl).initCause(ex);
1752             }
1753             if (!unshared) {
1754                 handles.setObject(enumHandle, result);
1755             }
1756         }
1757 
1758         handles.finish(enumHandle);
1759         passHandle = enumHandle;
1760         return result;
1761     }
1762 
1763     /**
1764      * Reads and returns "ordinary" (i.e., not a String, Class,
1765      * ObjectStreamClass, array, or enum constant) object, or null if object's
1766      * class is unresolvable (in which case a ClassNotFoundException will be
1767      * associated with object's handle).  Sets passHandle to object's assigned
1768      * handle.
1769      */
1770     private Object readOrdinaryObject(boolean unshared)
1771         throws IOException
1772     {
1773         if (bin.readByte() != TC_OBJECT) {
1774             throw new InternalError();
1775         }
1776 
1777         ObjectStreamClass desc = readClassDesc(false);
1778         desc.checkDeserialize();
1779 
1780         Class<?> cl = desc.forClass();
1781         if (cl == String.class || cl == Class.class
1782                 || cl == ObjectStreamClass.class) {
1783             throw new InvalidClassException("invalid class descriptor");
1784         }
1785 
1786         Object obj;
1787         try {
1788             obj = desc.isInstantiable() ? desc.newInstance() : null;
1789         } catch (Exception ex) {
1790             throw (IOException) new InvalidClassException(
1791                 desc.forClass().getName(),
1792                 "unable to create instance").initCause(ex);
1793         }
1794 
1795         passHandle = handles.assign(unshared ? unsharedMarker : obj);
1796         ClassNotFoundException resolveEx = desc.getResolveException();
1797         if (resolveEx != null) {
1798             handles.markException(passHandle, resolveEx);
1799         }
1800 
1801         if (desc.isExternalizable()) {
1802             readExternalData((Externalizable) obj, desc);
1803         } else {
1804             readSerialData(obj, desc);
1805         }
1806 
1807         handles.finish(passHandle);
1808 
1809         if (obj != null &&
1810             handles.lookupException(passHandle) == null &&
1811             desc.hasReadResolveMethod())
1812         {
1813             Object rep = desc.invokeReadResolve(obj);
1814             if (unshared && rep.getClass().isArray()) {
1815                 rep = cloneArray(rep);
1816             }
1817             if (rep != obj) {
1818                 handles.setObject(passHandle, obj = rep);
1819             }
1820         }
1821 
1822         return obj;
1823     }
1824 
1825     /**
1826      * If obj is non-null, reads externalizable data by invoking readExternal()
1827      * method of obj; otherwise, attempts to skip over externalizable data.
1828      * Expects that passHandle is set to obj's handle before this method is
1829      * called.
1830      */
1831     private void readExternalData(Externalizable obj, ObjectStreamClass desc)
1832         throws IOException
1833     {
1834         SerialCallbackContext oldContext = curContext;
1835         if (oldContext != null)
1836             oldContext.check();
1837         curContext = null;
1838         try {
1839             boolean blocked = desc.hasBlockExternalData();
1840             if (blocked) {
1841                 bin.setBlockDataMode(true);
1842             }
1843             if (obj != null) {
1844                 try {
1845                     obj.readExternal(this);
1846                 } catch (ClassNotFoundException ex) {
1847                     /*
1848                      * In most cases, the handle table has already propagated
1849                      * a CNFException to passHandle at this point; this mark
1850                      * call is included to address cases where the readExternal
1851                      * method has cons'ed and thrown a new CNFException of its
1852                      * own.
1853                      */
1854                      handles.markException(passHandle, ex);
1855                 }
1856             }
1857             if (blocked) {
1858                 skipCustomData();
1859             }
1860         } finally {
1861             if (oldContext != null)
1862                 oldContext.check();
1863             curContext = oldContext;
1864         }
1865         /*
1866          * At this point, if the externalizable data was not written in
1867          * block-data form and either the externalizable class doesn't exist
1868          * locally (i.e., obj == null) or readExternal() just threw a
1869          * CNFException, then the stream is probably in an inconsistent state,
1870          * since some (or all) of the externalizable data may not have been
1871          * consumed.  Since there's no "correct" action to take in this case,
1872          * we mimic the behavior of past serialization implementations and
1873          * blindly hope that the stream is in sync; if it isn't and additional
1874          * externalizable data remains in the stream, a subsequent read will
1875          * most likely throw a StreamCorruptedException.
1876          */
1877     }
1878 
1879     /**
1880      * Reads (or attempts to skip, if obj is null or is tagged with a
1881      * ClassNotFoundException) instance data for each serializable class of
1882      * object in stream, from superclass to subclass.  Expects that passHandle
1883      * is set to obj's handle before this method is called.
1884      */
1885     private void readSerialData(Object obj, ObjectStreamClass desc)
1886         throws IOException
1887     {
1888         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
1889         // Best effort Failure Atomicity; slotValues will be non-null if field
1890         // values can be set after reading all field data in the hierarchy.
1891         // Field values can only be set after reading all data if there are no
1892         // user observable methods in the hierarchy, readObject(NoData). The
1893         // top most Serializable class in the hierarchy can be skipped.
1894         FieldValues[] slotValues = null;
1895 
1896         boolean hasSpecialReadMethod = false;
1897         for (int i = 1; i < slots.length; i++) {
1898             ObjectStreamClass slotDesc = slots[i].desc;
1899             if (slotDesc.hasReadObjectMethod()
1900                   || slotDesc.hasReadObjectNoDataMethod()) {
1901                 hasSpecialReadMethod = true;
1902                 break;
1903             }
1904         }
1905         // No special read methods, can store values and defer setting.
1906         if (!hasSpecialReadMethod)
1907             slotValues = new FieldValues[slots.length];
1908 
1909         for (int i = 0; i < slots.length; i++) {
1910             ObjectStreamClass slotDesc = slots[i].desc;
1911 
1912             if (slots[i].hasData) {
1913                 if (obj == null || handles.lookupException(passHandle) != null) {
1914                     defaultReadFields(null, slotDesc); // skip field values
1915                 } else if (slotDesc.hasReadObjectMethod()) {
1916                     SerialCallbackContext oldContext = curContext;
1917                     if (oldContext != null)
1918                         oldContext.check();
1919                     try {
1920                         curContext = new SerialCallbackContext(obj, slotDesc);
1921 
1922                         bin.setBlockDataMode(true);
1923                         slotDesc.invokeReadObject(obj, this);
1924                     } catch (ClassNotFoundException ex) {
1925                         /*
1926                          * In most cases, the handle table has already
1927                          * propagated a CNFException to passHandle at this
1928                          * point; this mark call is included to address cases
1929                          * where the custom readObject method has cons'ed and
1930                          * thrown a new CNFException of its own.
1931                          */
1932                         handles.markException(passHandle, ex);
1933                     } finally {
1934                         curContext.setUsed();
1935                         if (oldContext!= null)
1936                             oldContext.check();
1937                         curContext = oldContext;
1938                     }
1939 
1940                     /*
1941                      * defaultDataEnd may have been set indirectly by custom
1942                      * readObject() method when calling defaultReadObject() or
1943                      * readFields(); clear it to restore normal read behavior.
1944                      */
1945                     defaultDataEnd = false;
1946                 } else {
1947                     FieldValues vals = defaultReadFields(obj, slotDesc);
1948                     if (slotValues != null) {
1949                         slotValues[i] = vals;
1950                     } else if (obj != null) {
1951                         defaultCheckFieldValues(obj, slotDesc, vals);
1952                         defaultSetFieldValues(obj, slotDesc, vals);
1953                     }
1954                 }
1955 
1956                 if (slotDesc.hasWriteObjectData()) {
1957                     skipCustomData();
1958                 } else {
1959                     bin.setBlockDataMode(false);
1960                 }
1961             } else {
1962                 if (obj != null &&
1963                     slotDesc.hasReadObjectNoDataMethod() &&
1964                     handles.lookupException(passHandle) == null)
1965                 {
1966                     slotDesc.invokeReadObjectNoData(obj);
1967                 }
1968             }
1969         }
1970 
1971         if (obj != null && slotValues != null) {
1972             // Check that the non-primitive types are assignable for all slots
1973             // before assigning.
1974             for (int i = 0; i < slots.length; i++) {
1975                 if (slotValues[i] != null)
1976                     defaultCheckFieldValues(obj, slots[i].desc, slotValues[i]);
1977             }
1978             for (int i = 0; i < slots.length; i++) {
1979                 if (slotValues[i] != null)
1980                     defaultSetFieldValues(obj, slots[i].desc, slotValues[i]);
1981             }
1982         }
1983     }
1984 
1985     /**
1986      * Skips over all block data and objects until TC_ENDBLOCKDATA is
1987      * encountered.
1988      */
1989     private void skipCustomData() throws IOException {
1990         int oldHandle = passHandle;
1991         for (;;) {
1992             if (bin.getBlockDataMode()) {
1993                 bin.skipBlockData();
1994                 bin.setBlockDataMode(false);
1995             }
1996             switch (bin.peekByte()) {
1997                 case TC_BLOCKDATA:
1998                 case TC_BLOCKDATALONG:
1999                     bin.setBlockDataMode(true);
2000                     break;
2001 
2002                 case TC_ENDBLOCKDATA:
2003                     bin.readByte();
2004                     passHandle = oldHandle;
2005                     return;
2006 
2007                 default:
2008                     readObject0(false);
2009                     break;
2010             }
2011         }
2012     }
2013 
2014     private class FieldValues {
2015         final byte[] primValues;
2016         final Object[] objValues;
2017 
2018         FieldValues(byte[] primValues, Object[] objValues) {
2019             this.primValues = primValues;
2020             this.objValues = objValues;
2021         }
2022     }
2023 
2024     /**
2025      * Reads in values of serializable fields declared by given class
2026      * descriptor. Expects that passHandle is set to obj's handle before this
2027      * method is called.
2028      */
2029     private FieldValues defaultReadFields(Object obj, ObjectStreamClass desc)
2030         throws IOException
2031     {
2032         Class<?> cl = desc.forClass();
2033         if (cl != null && obj != null && !cl.isInstance(obj)) {
2034             throw new ClassCastException();
2035         }
2036 
2037         byte[] primVals = null;
2038         int primDataSize = desc.getPrimDataSize();
2039         if (primDataSize > 0) {
2040             primVals = new byte[primDataSize];
2041             bin.readFully(primVals, 0, primDataSize, false);
2042         }
2043 
2044         Object[] objVals = null;
2045         int numObjFields = desc.getNumObjFields();
2046         if (numObjFields > 0) {
2047             int objHandle = passHandle;
2048             ObjectStreamField[] fields = desc.getFields(false);
2049             objVals = new Object[numObjFields];
2050             int numPrimFields = fields.length - objVals.length;
2051             for (int i = 0; i < objVals.length; i++) {
2052                 ObjectStreamField f = fields[numPrimFields + i];
2053                 objVals[i] = readObject0(f.isUnshared());
2054                 if (f.getField() != null) {
2055                     handles.markDependency(objHandle, passHandle);
2056                 }
2057             }
2058             passHandle = objHandle;
2059         }
2060 
2061         return new FieldValues(primVals, objVals);
2062     }
2063 
2064     /** Throws ClassCastException if any value is not assignable. */
2065     private void defaultCheckFieldValues(Object obj, ObjectStreamClass desc,
2066                                          FieldValues values) {
2067         Object[] objectValues = values.objValues;
2068         if (objectValues != null)
2069             desc.checkObjFieldValueTypes(obj, objectValues);
2070     }
2071 
2072     /** Sets field values in obj. */
2073     private void defaultSetFieldValues(Object obj, ObjectStreamClass desc,
2074                                        FieldValues values) {
2075         byte[] primValues = values.primValues;
2076         Object[] objectValues = values.objValues;
2077 
2078         if (primValues != null)
2079             desc.setPrimFieldValues(obj, primValues);
2080         if (objectValues != null)
2081             desc.setObjFieldValues(obj, objectValues);
2082     }
2083 
2084     /**
2085      * Reads in and returns IOException that caused serialization to abort.
2086      * All stream state is discarded prior to reading in fatal exception.  Sets
2087      * passHandle to fatal exception's handle.
2088      */
2089     private IOException readFatalException() throws IOException {
2090         if (bin.readByte() != TC_EXCEPTION) {
2091             throw new InternalError();
2092         }
2093         clear();
2094         return (IOException) readObject0(false);
2095     }
2096 
2097     /**
2098      * If recursion depth is 0, clears internal data structures; otherwise,
2099      * throws a StreamCorruptedException.  This method is called when a
2100      * TC_RESET typecode is encountered.
2101      */
2102     private void handleReset() throws StreamCorruptedException {
2103         if (depth > 0) {
2104             throw new StreamCorruptedException(
2105                 "unexpected reset; recursion depth: " + depth);
2106         }
2107         clear();
2108     }
2109 
2110     /**
2111      * Converts specified span of bytes into float values.
2112      */
2113     // REMIND: remove once hotspot inlines Float.intBitsToFloat
2114     private static native void bytesToFloats(byte[] src, int srcpos,
2115                                              float[] dst, int dstpos,
2116                                              int nfloats);
2117 
2118     /**
2119      * Converts specified span of bytes into double values.
2120      */
2121     // REMIND: remove once hotspot inlines Double.longBitsToDouble
2122     private static native void bytesToDoubles(byte[] src, int srcpos,
2123                                               double[] dst, int dstpos,
2124                                               int ndoubles);
2125 
2126     /**
2127      * Returns the first non-null class loader (not counting class loaders of
2128      * generated reflection implementation classes) up the execution stack, or
2129      * null if only code from the null class loader is on the stack.  This
2130      * method is also called via reflection by the following RMI-IIOP class:
2131      *
2132      *     com.sun.corba.se.internal.util.JDKClassLoader
2133      *
2134      * This method should not be removed or its signature changed without
2135      * corresponding modifications to the above class.
2136      */
2137     private static ClassLoader latestUserDefinedLoader() {
2138         return jdk.internal.misc.VM.latestUserDefinedLoader();
2139     }
2140 
2141     /**
2142      * Default GetField implementation.
2143      */
2144     private class GetFieldImpl extends GetField {
2145 
2146         /** class descriptor describing serializable fields */
2147         private final ObjectStreamClass desc;
2148         /** primitive field values */
2149         private final byte[] primVals;
2150         /** object field values */
2151         private final Object[] objVals;
2152         /** object field value handles */
2153         private final int[] objHandles;
2154 
2155         /**
2156          * Creates GetFieldImpl object for reading fields defined in given
2157          * class descriptor.
2158          */
2159         GetFieldImpl(ObjectStreamClass desc) {
2160             this.desc = desc;
2161             primVals = new byte[desc.getPrimDataSize()];
2162             objVals = new Object[desc.getNumObjFields()];
2163             objHandles = new int[objVals.length];
2164         }
2165 
2166         public ObjectStreamClass getObjectStreamClass() {
2167             return desc;
2168         }
2169 
2170         public boolean defaulted(String name) throws IOException {
2171             return (getFieldOffset(name, null) < 0);
2172         }
2173 
2174         public boolean get(String name, boolean val) throws IOException {
2175             int off = getFieldOffset(name, Boolean.TYPE);
2176             return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
2177         }
2178 
2179         public byte get(String name, byte val) throws IOException {
2180             int off = getFieldOffset(name, Byte.TYPE);
2181             return (off >= 0) ? primVals[off] : val;
2182         }
2183 
2184         public char get(String name, char val) throws IOException {
2185             int off = getFieldOffset(name, Character.TYPE);
2186             return (off >= 0) ? Bits.getChar(primVals, off) : val;
2187         }
2188 
2189         public short get(String name, short val) throws IOException {
2190             int off = getFieldOffset(name, Short.TYPE);
2191             return (off >= 0) ? Bits.getShort(primVals, off) : val;
2192         }
2193 
2194         public int get(String name, int val) throws IOException {
2195             int off = getFieldOffset(name, Integer.TYPE);
2196             return (off >= 0) ? Bits.getInt(primVals, off) : val;
2197         }
2198 
2199         public float get(String name, float val) throws IOException {
2200             int off = getFieldOffset(name, Float.TYPE);
2201             return (off >= 0) ? Bits.getFloat(primVals, off) : val;
2202         }
2203 
2204         public long get(String name, long val) throws IOException {
2205             int off = getFieldOffset(name, Long.TYPE);
2206             return (off >= 0) ? Bits.getLong(primVals, off) : val;
2207         }
2208 
2209         public double get(String name, double val) throws IOException {
2210             int off = getFieldOffset(name, Double.TYPE);
2211             return (off >= 0) ? Bits.getDouble(primVals, off) : val;
2212         }
2213 
2214         public Object get(String name, Object val) throws IOException {
2215             int off = getFieldOffset(name, Object.class);
2216             if (off >= 0) {
2217                 int objHandle = objHandles[off];
2218                 handles.markDependency(passHandle, objHandle);
2219                 return (handles.lookupException(objHandle) == null) ?
2220                     objVals[off] : null;
2221             } else {
2222                 return val;
2223             }
2224         }
2225 
2226         /**
2227          * Reads primitive and object field values from stream.
2228          */
2229         void readFields() throws IOException {
2230             bin.readFully(primVals, 0, primVals.length, false);
2231 
2232             int oldHandle = passHandle;
2233             ObjectStreamField[] fields = desc.getFields(false);
2234             int numPrimFields = fields.length - objVals.length;
2235             for (int i = 0; i < objVals.length; i++) {
2236                 objVals[i] =
2237                     readObject0(fields[numPrimFields + i].isUnshared());
2238                 objHandles[i] = passHandle;
2239             }
2240             passHandle = oldHandle;
2241         }
2242 
2243         /**
2244          * Returns offset of field with given name and type.  A specified type
2245          * of null matches all types, Object.class matches all non-primitive
2246          * types, and any other non-null type matches assignable types only.
2247          * If no matching field is found in the (incoming) class
2248          * descriptor but a matching field is present in the associated local
2249          * class descriptor, returns -1.  Throws IllegalArgumentException if
2250          * neither incoming nor local class descriptor contains a match.
2251          */
2252         private int getFieldOffset(String name, Class<?> type) {
2253             ObjectStreamField field = desc.getField(name, type);
2254             if (field != null) {
2255                 return field.getOffset();
2256             } else if (desc.getLocalDesc().getField(name, type) != null) {
2257                 return -1;
2258             } else {
2259                 throw new IllegalArgumentException("no such field " + name +
2260                                                    " with type " + type);
2261             }
2262         }
2263     }
2264 
2265     /**
2266      * Prioritized list of callbacks to be performed once object graph has been
2267      * completely deserialized.
2268      */
2269     private static class ValidationList {
2270 
2271         private static class Callback {
2272             final ObjectInputValidation obj;
2273             final int priority;
2274             Callback next;
2275             final AccessControlContext acc;
2276 
2277             Callback(ObjectInputValidation obj, int priority, Callback next,
2278                 AccessControlContext acc)
2279             {
2280                 this.obj = obj;
2281                 this.priority = priority;
2282                 this.next = next;
2283                 this.acc = acc;
2284             }
2285         }
2286 
2287         /** linked list of callbacks */
2288         private Callback list;
2289 
2290         /**
2291          * Creates new (empty) ValidationList.
2292          */
2293         ValidationList() {
2294         }
2295 
2296         /**
2297          * Registers callback.  Throws InvalidObjectException if callback
2298          * object is null.
2299          */
2300         void register(ObjectInputValidation obj, int priority)
2301             throws InvalidObjectException
2302         {
2303             if (obj == null) {
2304                 throw new InvalidObjectException("null callback");
2305             }
2306 
2307             Callback prev = null, cur = list;
2308             while (cur != null && priority < cur.priority) {
2309                 prev = cur;
2310                 cur = cur.next;
2311             }
2312             AccessControlContext acc = AccessController.getContext();
2313             if (prev != null) {
2314                 prev.next = new Callback(obj, priority, cur, acc);
2315             } else {
2316                 list = new Callback(obj, priority, list, acc);
2317             }
2318         }
2319 
2320         /**
2321          * Invokes all registered callbacks and clears the callback list.
2322          * Callbacks with higher priorities are called first; those with equal
2323          * priorities may be called in any order.  If any of the callbacks
2324          * throws an InvalidObjectException, the callback process is terminated
2325          * and the exception propagated upwards.
2326          */
2327         void doCallbacks() throws InvalidObjectException {
2328             try {
2329                 while (list != null) {
2330                     AccessController.doPrivileged(
2331                         new PrivilegedExceptionAction<>()
2332                     {
2333                         public Void run() throws InvalidObjectException {
2334                             list.obj.validateObject();
2335                             return null;
2336                         }
2337                     }, list.acc);
2338                     list = list.next;
2339                 }
2340             } catch (PrivilegedActionException ex) {
2341                 list = null;
2342                 throw (InvalidObjectException) ex.getException();
2343             }
2344         }
2345 
2346         /**
2347          * Resets the callback list to its initial (empty) state.
2348          */
2349         public void clear() {
2350             list = null;
2351         }
2352     }
2353 
2354     /**
2355      * Input stream supporting single-byte peek operations.
2356      */
2357     private static class PeekInputStream extends InputStream {
2358 
2359         /** underlying stream */
2360         private final InputStream in;
2361         /** peeked byte */
2362         private int peekb = -1;
2363 
2364         /**
2365          * Creates new PeekInputStream on top of given underlying stream.
2366          */
2367         PeekInputStream(InputStream in) {
2368             this.in = in;
2369         }
2370 
2371         /**
2372          * Peeks at next byte value in stream.  Similar to read(), except
2373          * that it does not consume the read value.
2374          */
2375         int peek() throws IOException {
2376             return (peekb >= 0) ? peekb : (peekb = in.read());
2377         }
2378 
2379         public int read() throws IOException {
2380             if (peekb >= 0) {
2381                 int v = peekb;
2382                 peekb = -1;
2383                 return v;
2384             } else {
2385                 return in.read();
2386             }
2387         }
2388 
2389         public int read(byte[] b, int off, int len) throws IOException {
2390             if (len == 0) {
2391                 return 0;
2392             } else if (peekb < 0) {
2393                 return in.read(b, off, len);
2394             } else {
2395                 b[off++] = (byte) peekb;
2396                 len--;
2397                 peekb = -1;
2398                 int n = in.read(b, off, len);
2399                 return (n >= 0) ? (n + 1) : 1;
2400             }
2401         }
2402 
2403         void readFully(byte[] b, int off, int len) throws IOException {
2404             int n = 0;
2405             while (n < len) {
2406                 int count = read(b, off + n, len - n);
2407                 if (count < 0) {
2408                     throw new EOFException();
2409                 }
2410                 n += count;
2411             }
2412         }
2413 
2414         public long skip(long n) throws IOException {
2415             if (n <= 0) {
2416                 return 0;
2417             }
2418             int skipped = 0;
2419             if (peekb >= 0) {
2420                 peekb = -1;
2421                 skipped++;
2422                 n--;
2423             }
2424             return skipped + in.skip(n);
2425         }
2426 
2427         public int available() throws IOException {
2428             return in.available() + ((peekb >= 0) ? 1 : 0);
2429         }
2430 
2431         public void close() throws IOException {
2432             in.close();
2433         }
2434     }
2435 
2436     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
2437 
2438     /**
2439      * Performs a "freeze" action, required to adhere to final field semantics.
2440      *
2441      * <p> This method can be called unconditionally before returning the graph,
2442      * from the topmost readObject call, since it is expected that the
2443      * additional cost of the freeze action is negligible compared to
2444      * reconstituting even the most simple graph.
2445      *
2446      * <p> Nested calls to readObject do not issue freeze actions because the
2447      * sub-graph returned from a nested call is not guaranteed to be fully
2448      * initialized yet (possible cycles).
2449      */
2450     private void freeze() {
2451         // Issue a StoreStore|StoreLoad fence, which is at least sufficient
2452         // to provide final-freeze semantics.
2453         UNSAFE.storeFence();
2454     }
2455 
2456     /**
2457      * Input stream with two modes: in default mode, inputs data written in the
2458      * same format as DataOutputStream; in "block data" mode, inputs data
2459      * bracketed by block data markers (see object serialization specification
2460      * for details).  Buffering depends on block data mode: when in default
2461      * mode, no data is buffered in advance; when in block data mode, all data
2462      * for the current data block is read in at once (and buffered).
2463      */
2464     private class BlockDataInputStream
2465         extends InputStream implements DataInput
2466     {
2467         /** maximum data block length */
2468         private static final int MAX_BLOCK_SIZE = 1024;
2469         /** maximum data block header length */
2470         private static final int MAX_HEADER_SIZE = 5;
2471         /** (tunable) length of char buffer (for reading strings) */
2472         private static final int CHAR_BUF_SIZE = 256;
2473         /** readBlockHeader() return value indicating header read may block */
2474         private static final int HEADER_BLOCKED = -2;
2475 
2476         /** buffer for reading general/block data */
2477         private final byte[] buf = new byte[MAX_BLOCK_SIZE];
2478         /** buffer for reading block data headers */
2479         private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
2480         /** char buffer for fast string reads */
2481         private final char[] cbuf = new char[CHAR_BUF_SIZE];
2482 
2483         /** block data mode */
2484         private boolean blkmode = false;
2485 
2486         // block data state fields; values meaningful only when blkmode true
2487         /** current offset into buf */
2488         private int pos = 0;
2489         /** end offset of valid data in buf, or -1 if no more block data */
2490         private int end = -1;
2491         /** number of bytes in current block yet to be read from stream */
2492         private int unread = 0;
2493 
2494         /** underlying stream (wrapped in peekable filter stream) */
2495         private final PeekInputStream in;
2496         /** loopback stream (for data reads that span data blocks) */
2497         private final DataInputStream din;
2498 
2499         /**
2500          * Creates new BlockDataInputStream on top of given underlying stream.
2501          * Block data mode is turned off by default.
2502          */
2503         BlockDataInputStream(InputStream in) {
2504             this.in = new PeekInputStream(in);
2505             din = new DataInputStream(this);
2506         }
2507 
2508         /**
2509          * Sets block data mode to the given mode (true == on, false == off)
2510          * and returns the previous mode value.  If the new mode is the same as
2511          * the old mode, no action is taken.  Throws IllegalStateException if
2512          * block data mode is being switched from on to off while unconsumed
2513          * block data is still present in the stream.
2514          */
2515         boolean setBlockDataMode(boolean newmode) throws IOException {
2516             if (blkmode == newmode) {
2517                 return blkmode;
2518             }
2519             if (newmode) {
2520                 pos = 0;
2521                 end = 0;
2522                 unread = 0;
2523             } else if (pos < end) {
2524                 throw new IllegalStateException("unread block data");
2525             }
2526             blkmode = newmode;
2527             return !blkmode;
2528         }
2529 
2530         /**
2531          * Returns true if the stream is currently in block data mode, false
2532          * otherwise.
2533          */
2534         boolean getBlockDataMode() {
2535             return blkmode;
2536         }
2537 
2538         /**
2539          * If in block data mode, skips to the end of the current group of data
2540          * blocks (but does not unset block data mode).  If not in block data
2541          * mode, throws an IllegalStateException.
2542          */
2543         void skipBlockData() throws IOException {
2544             if (!blkmode) {
2545                 throw new IllegalStateException("not in block data mode");
2546             }
2547             while (end >= 0) {
2548                 refill();
2549             }
2550         }
2551 
2552         /**
2553          * Attempts to read in the next block data header (if any).  If
2554          * canBlock is false and a full header cannot be read without possibly
2555          * blocking, returns HEADER_BLOCKED, else if the next element in the
2556          * stream is a block data header, returns the block data length
2557          * specified by the header, else returns -1.
2558          */
2559         private int readBlockHeader(boolean canBlock) throws IOException {
2560             if (defaultDataEnd) {
2561                 /*
2562                  * Fix for 4360508: stream is currently at the end of a field
2563                  * value block written via default serialization; since there
2564                  * is no terminating TC_ENDBLOCKDATA tag, simulate
2565                  * end-of-custom-data behavior explicitly.
2566                  */
2567                 return -1;
2568             }
2569             try {
2570                 for (;;) {
2571                     int avail = canBlock ? Integer.MAX_VALUE : in.available();
2572                     if (avail == 0) {
2573                         return HEADER_BLOCKED;
2574                     }
2575 
2576                     int tc = in.peek();
2577                     switch (tc) {
2578                         case TC_BLOCKDATA:
2579                             if (avail < 2) {
2580                                 return HEADER_BLOCKED;
2581                             }
2582                             in.readFully(hbuf, 0, 2);
2583                             return hbuf[1] & 0xFF;
2584 
2585                         case TC_BLOCKDATALONG:
2586                             if (avail < 5) {
2587                                 return HEADER_BLOCKED;
2588                             }
2589                             in.readFully(hbuf, 0, 5);
2590                             int len = Bits.getInt(hbuf, 1);
2591                             if (len < 0) {
2592                                 throw new StreamCorruptedException(
2593                                     "illegal block data header length: " +
2594                                     len);
2595                             }
2596                             return len;
2597 
2598                         /*
2599                          * TC_RESETs may occur in between data blocks.
2600                          * Unfortunately, this case must be parsed at a lower
2601                          * level than other typecodes, since primitive data
2602                          * reads may span data blocks separated by a TC_RESET.
2603                          */
2604                         case TC_RESET:
2605                             in.read();
2606                             handleReset();
2607                             break;
2608 
2609                         default:
2610                             if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
2611                                 throw new StreamCorruptedException(
2612                                     String.format("invalid type code: %02X",
2613                                     tc));
2614                             }
2615                             return -1;
2616                     }
2617                 }
2618             } catch (EOFException ex) {
2619                 throw new StreamCorruptedException(
2620                     "unexpected EOF while reading block data header");
2621             }
2622         }
2623 
2624         /**
2625          * Refills internal buffer buf with block data.  Any data in buf at the
2626          * time of the call is considered consumed.  Sets the pos, end, and
2627          * unread fields to reflect the new amount of available block data; if
2628          * the next element in the stream is not a data block, sets pos and
2629          * unread to 0 and end to -1.
2630          */
2631         private void refill() throws IOException {
2632             try {
2633                 do {
2634                     pos = 0;
2635                     if (unread > 0) {
2636                         int n =
2637                             in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE));
2638                         if (n >= 0) {
2639                             end = n;
2640                             unread -= n;
2641                         } else {
2642                             throw new StreamCorruptedException(
2643                                 "unexpected EOF in middle of data block");
2644                         }
2645                     } else {
2646                         int n = readBlockHeader(true);
2647                         if (n >= 0) {
2648                             end = 0;
2649                             unread = n;
2650                         } else {
2651                             end = -1;
2652                             unread = 0;
2653                         }
2654                     }
2655                 } while (pos == end);
2656             } catch (IOException ex) {
2657                 pos = 0;
2658                 end = -1;
2659                 unread = 0;
2660                 throw ex;
2661             }
2662         }
2663 
2664         /**
2665          * If in block data mode, returns the number of unconsumed bytes
2666          * remaining in the current data block.  If not in block data mode,
2667          * throws an IllegalStateException.
2668          */
2669         int currentBlockRemaining() {
2670             if (blkmode) {
2671                 return (end >= 0) ? (end - pos) + unread : 0;
2672             } else {
2673                 throw new IllegalStateException();
2674             }
2675         }
2676 
2677         /**
2678          * Peeks at (but does not consume) and returns the next byte value in
2679          * the stream, or -1 if the end of the stream/block data (if in block
2680          * data mode) has been reached.
2681          */
2682         int peek() throws IOException {
2683             if (blkmode) {
2684                 if (pos == end) {
2685                     refill();
2686                 }
2687                 return (end >= 0) ? (buf[pos] & 0xFF) : -1;
2688             } else {
2689                 return in.peek();
2690             }
2691         }
2692 
2693         /**
2694          * Peeks at (but does not consume) and returns the next byte value in
2695          * the stream, or throws EOFException if end of stream/block data has
2696          * been reached.
2697          */
2698         byte peekByte() throws IOException {
2699             int val = peek();
2700             if (val < 0) {
2701                 throw new EOFException();
2702             }
2703             return (byte) val;
2704         }
2705 
2706 
2707         /* ----------------- generic input stream methods ------------------ */
2708         /*
2709          * The following methods are equivalent to their counterparts in
2710          * InputStream, except that they interpret data block boundaries and
2711          * read the requested data from within data blocks when in block data
2712          * mode.
2713          */
2714 
2715         public int read() throws IOException {
2716             if (blkmode) {
2717                 if (pos == end) {
2718                     refill();
2719                 }
2720                 return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
2721             } else {
2722                 return in.read();
2723             }
2724         }
2725 
2726         public int read(byte[] b, int off, int len) throws IOException {
2727             return read(b, off, len, false);
2728         }
2729 
2730         public long skip(long len) throws IOException {
2731             long remain = len;
2732             while (remain > 0) {
2733                 if (blkmode) {
2734                     if (pos == end) {
2735                         refill();
2736                     }
2737                     if (end < 0) {
2738                         break;
2739                     }
2740                     int nread = (int) Math.min(remain, end - pos);
2741                     remain -= nread;
2742                     pos += nread;
2743                 } else {
2744                     int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
2745                     if ((nread = in.read(buf, 0, nread)) < 0) {
2746                         break;
2747                     }
2748                     remain -= nread;
2749                 }
2750             }
2751             return len - remain;
2752         }
2753 
2754         public int available() throws IOException {
2755             if (blkmode) {
2756                 if ((pos == end) && (unread == 0)) {
2757                     int n;
2758                     while ((n = readBlockHeader(false)) == 0) ;
2759                     switch (n) {
2760                         case HEADER_BLOCKED:
2761                             break;
2762 
2763                         case -1:
2764                             pos = 0;
2765                             end = -1;
2766                             break;
2767 
2768                         default:
2769                             pos = 0;
2770                             end = 0;
2771                             unread = n;
2772                             break;
2773                     }
2774                 }
2775                 // avoid unnecessary call to in.available() if possible
2776                 int unreadAvail = (unread > 0) ?
2777                     Math.min(in.available(), unread) : 0;
2778                 return (end >= 0) ? (end - pos) + unreadAvail : 0;
2779             } else {
2780                 return in.available();
2781             }
2782         }
2783 
2784         public void close() throws IOException {
2785             if (blkmode) {
2786                 pos = 0;
2787                 end = -1;
2788                 unread = 0;
2789             }
2790             in.close();
2791         }
2792 
2793         /**
2794          * Attempts to read len bytes into byte array b at offset off.  Returns
2795          * the number of bytes read, or -1 if the end of stream/block data has
2796          * been reached.  If copy is true, reads values into an intermediate
2797          * buffer before copying them to b (to avoid exposing a reference to
2798          * b).
2799          */
2800         int read(byte[] b, int off, int len, boolean copy) throws IOException {
2801             if (len == 0) {
2802                 return 0;
2803             } else if (blkmode) {
2804                 if (pos == end) {
2805                     refill();
2806                 }
2807                 if (end < 0) {
2808                     return -1;
2809                 }
2810                 int nread = Math.min(len, end - pos);
2811                 System.arraycopy(buf, pos, b, off, nread);
2812                 pos += nread;
2813                 return nread;
2814             } else if (copy) {
2815                 int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE));
2816                 if (nread > 0) {
2817                     System.arraycopy(buf, 0, b, off, nread);
2818                 }
2819                 return nread;
2820             } else {
2821                 return in.read(b, off, len);
2822             }
2823         }
2824 
2825         /* ----------------- primitive data input methods ------------------ */
2826         /*
2827          * The following methods are equivalent to their counterparts in
2828          * DataInputStream, except that they interpret data block boundaries
2829          * and read the requested data from within data blocks when in block
2830          * data mode.
2831          */
2832 
2833         public void readFully(byte[] b) throws IOException {
2834             readFully(b, 0, b.length, false);
2835         }
2836 
2837         public void readFully(byte[] b, int off, int len) throws IOException {
2838             readFully(b, off, len, false);
2839         }
2840 
2841         public void readFully(byte[] b, int off, int len, boolean copy)
2842             throws IOException
2843         {
2844             while (len > 0) {
2845                 int n = read(b, off, len, copy);
2846                 if (n < 0) {
2847                     throw new EOFException();
2848                 }
2849                 off += n;
2850                 len -= n;
2851             }
2852         }
2853 
2854         public int skipBytes(int n) throws IOException {
2855             return din.skipBytes(n);
2856         }
2857 
2858         public boolean readBoolean() throws IOException {
2859             int v = read();
2860             if (v < 0) {
2861                 throw new EOFException();
2862             }
2863             return (v != 0);
2864         }
2865 
2866         public byte readByte() throws IOException {
2867             int v = read();
2868             if (v < 0) {
2869                 throw new EOFException();
2870             }
2871             return (byte) v;
2872         }
2873 
2874         public int readUnsignedByte() throws IOException {
2875             int v = read();
2876             if (v < 0) {
2877                 throw new EOFException();
2878             }
2879             return v;
2880         }
2881 
2882         public char readChar() throws IOException {
2883             if (!blkmode) {
2884                 pos = 0;
2885                 in.readFully(buf, 0, 2);
2886             } else if (end - pos < 2) {
2887                 return din.readChar();
2888             }
2889             char v = Bits.getChar(buf, pos);
2890             pos += 2;
2891             return v;
2892         }
2893 
2894         public short readShort() throws IOException {
2895             if (!blkmode) {
2896                 pos = 0;
2897                 in.readFully(buf, 0, 2);
2898             } else if (end - pos < 2) {
2899                 return din.readShort();
2900             }
2901             short v = Bits.getShort(buf, pos);
2902             pos += 2;
2903             return v;
2904         }
2905 
2906         public int readUnsignedShort() throws IOException {
2907             if (!blkmode) {
2908                 pos = 0;
2909                 in.readFully(buf, 0, 2);
2910             } else if (end - pos < 2) {
2911                 return din.readUnsignedShort();
2912             }
2913             int v = Bits.getShort(buf, pos) & 0xFFFF;
2914             pos += 2;
2915             return v;
2916         }
2917 
2918         public int readInt() throws IOException {
2919             if (!blkmode) {
2920                 pos = 0;
2921                 in.readFully(buf, 0, 4);
2922             } else if (end - pos < 4) {
2923                 return din.readInt();
2924             }
2925             int v = Bits.getInt(buf, pos);
2926             pos += 4;
2927             return v;
2928         }
2929 
2930         public float readFloat() throws IOException {
2931             if (!blkmode) {
2932                 pos = 0;
2933                 in.readFully(buf, 0, 4);
2934             } else if (end - pos < 4) {
2935                 return din.readFloat();
2936             }
2937             float v = Bits.getFloat(buf, pos);
2938             pos += 4;
2939             return v;
2940         }
2941 
2942         public long readLong() throws IOException {
2943             if (!blkmode) {
2944                 pos = 0;
2945                 in.readFully(buf, 0, 8);
2946             } else if (end - pos < 8) {
2947                 return din.readLong();
2948             }
2949             long v = Bits.getLong(buf, pos);
2950             pos += 8;
2951             return v;
2952         }
2953 
2954         public double readDouble() throws IOException {
2955             if (!blkmode) {
2956                 pos = 0;
2957                 in.readFully(buf, 0, 8);
2958             } else if (end - pos < 8) {
2959                 return din.readDouble();
2960             }
2961             double v = Bits.getDouble(buf, pos);
2962             pos += 8;
2963             return v;
2964         }
2965 
2966         public String readUTF() throws IOException {
2967             return readUTFBody(readUnsignedShort());
2968         }
2969 
2970         @SuppressWarnings("deprecation")
2971         public String readLine() throws IOException {
2972             return din.readLine();      // deprecated, not worth optimizing
2973         }
2974 
2975         /* -------------- primitive data array input methods --------------- */
2976         /*
2977          * The following methods read in spans of primitive data values.
2978          * Though equivalent to calling the corresponding primitive read
2979          * methods repeatedly, these methods are optimized for reading groups
2980          * of primitive data values more efficiently.
2981          */
2982 
2983         void readBooleans(boolean[] v, int off, int len) throws IOException {
2984             int stop, endoff = off + len;
2985             while (off < endoff) {
2986                 if (!blkmode) {
2987                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
2988                     in.readFully(buf, 0, span);
2989                     stop = off + span;
2990                     pos = 0;
2991                 } else if (end - pos < 1) {
2992                     v[off++] = din.readBoolean();
2993                     continue;
2994                 } else {
2995                     stop = Math.min(endoff, off + end - pos);
2996                 }
2997 
2998                 while (off < stop) {
2999                     v[off++] = Bits.getBoolean(buf, pos++);
3000                 }
3001             }
3002         }
3003 
3004         void readChars(char[] v, int off, int len) throws IOException {
3005             int stop, endoff = off + len;
3006             while (off < endoff) {
3007                 if (!blkmode) {
3008                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
3009                     in.readFully(buf, 0, span << 1);
3010                     stop = off + span;
3011                     pos = 0;
3012                 } else if (end - pos < 2) {
3013                     v[off++] = din.readChar();
3014                     continue;
3015                 } else {
3016                     stop = Math.min(endoff, off + ((end - pos) >> 1));
3017                 }
3018 
3019                 while (off < stop) {
3020                     v[off++] = Bits.getChar(buf, pos);
3021                     pos += 2;
3022                 }
3023             }
3024         }
3025 
3026         void readShorts(short[] v, int off, int len) throws IOException {
3027             int stop, endoff = off + len;
3028             while (off < endoff) {
3029                 if (!blkmode) {
3030                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
3031                     in.readFully(buf, 0, span << 1);
3032                     stop = off + span;
3033                     pos = 0;
3034                 } else if (end - pos < 2) {
3035                     v[off++] = din.readShort();
3036                     continue;
3037                 } else {
3038                     stop = Math.min(endoff, off + ((end - pos) >> 1));
3039                 }
3040 
3041                 while (off < stop) {
3042                     v[off++] = Bits.getShort(buf, pos);
3043                     pos += 2;
3044                 }
3045             }
3046         }
3047 
3048         void readInts(int[] v, int off, int len) throws IOException {
3049             int stop, endoff = off + len;
3050             while (off < endoff) {
3051                 if (!blkmode) {
3052                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
3053                     in.readFully(buf, 0, span << 2);
3054                     stop = off + span;
3055                     pos = 0;
3056                 } else if (end - pos < 4) {
3057                     v[off++] = din.readInt();
3058                     continue;
3059                 } else {
3060                     stop = Math.min(endoff, off + ((end - pos) >> 2));
3061                 }
3062 
3063                 while (off < stop) {
3064                     v[off++] = Bits.getInt(buf, pos);
3065                     pos += 4;
3066                 }
3067             }
3068         }
3069 
3070         void readFloats(float[] v, int off, int len) throws IOException {
3071             int span, endoff = off + len;
3072             while (off < endoff) {
3073                 if (!blkmode) {
3074                     span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
3075                     in.readFully(buf, 0, span << 2);
3076                     pos = 0;
3077                 } else if (end - pos < 4) {
3078                     v[off++] = din.readFloat();
3079                     continue;
3080                 } else {
3081                     span = Math.min(endoff - off, ((end - pos) >> 2));
3082                 }
3083 
3084                 bytesToFloats(buf, pos, v, off, span);
3085                 off += span;
3086                 pos += span << 2;
3087             }
3088         }
3089 
3090         void readLongs(long[] v, int off, int len) throws IOException {
3091             int stop, endoff = off + len;
3092             while (off < endoff) {
3093                 if (!blkmode) {
3094                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
3095                     in.readFully(buf, 0, span << 3);
3096                     stop = off + span;
3097                     pos = 0;
3098                 } else if (end - pos < 8) {
3099                     v[off++] = din.readLong();
3100                     continue;
3101                 } else {
3102                     stop = Math.min(endoff, off + ((end - pos) >> 3));
3103                 }
3104 
3105                 while (off < stop) {
3106                     v[off++] = Bits.getLong(buf, pos);
3107                     pos += 8;
3108                 }
3109             }
3110         }
3111 
3112         void readDoubles(double[] v, int off, int len) throws IOException {
3113             int span, endoff = off + len;
3114             while (off < endoff) {
3115                 if (!blkmode) {
3116                     span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
3117                     in.readFully(buf, 0, span << 3);
3118                     pos = 0;
3119                 } else if (end - pos < 8) {
3120                     v[off++] = din.readDouble();
3121                     continue;
3122                 } else {
3123                     span = Math.min(endoff - off, ((end - pos) >> 3));
3124                 }
3125 
3126                 bytesToDoubles(buf, pos, v, off, span);
3127                 off += span;
3128                 pos += span << 3;
3129             }
3130         }
3131 
3132         /**
3133          * Reads in string written in "long" UTF format.  "Long" UTF format is
3134          * identical to standard UTF, except that it uses an 8 byte header
3135          * (instead of the standard 2 bytes) to convey the UTF encoding length.
3136          */
3137         String readLongUTF() throws IOException {
3138             return readUTFBody(readLong());
3139         }
3140 
3141         /**
3142          * Reads in the "body" (i.e., the UTF representation minus the 2-byte
3143          * or 8-byte length header) of a UTF encoding, which occupies the next
3144          * utflen bytes.
3145          */
3146         private String readUTFBody(long utflen) throws IOException {
3147             StringBuilder sbuf;
3148             if (utflen > 0 && utflen < Integer.MAX_VALUE) {
3149                 // a reasonable initial capacity based on the UTF length
3150                 int initialCapacity = Math.min((int)utflen, 0xFFFF);
3151                 sbuf = new StringBuilder(initialCapacity);
3152             } else {
3153                 sbuf = new StringBuilder();
3154             }
3155 
3156             if (!blkmode) {
3157                 end = pos = 0;
3158             }
3159 
3160             while (utflen > 0) {
3161                 int avail = end - pos;
3162                 if (avail >= 3 || (long) avail == utflen) {
3163                     utflen -= readUTFSpan(sbuf, utflen);
3164                 } else {
3165                     if (blkmode) {
3166                         // near block boundary, read one byte at a time
3167                         utflen -= readUTFChar(sbuf, utflen);
3168                     } else {
3169                         // shift and refill buffer manually
3170                         if (avail > 0) {
3171                             System.arraycopy(buf, pos, buf, 0, avail);
3172                         }
3173                         pos = 0;
3174                         end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
3175                         in.readFully(buf, avail, end - avail);
3176                     }
3177                 }
3178             }
3179 
3180             return sbuf.toString();
3181         }
3182 
3183         /**
3184          * Reads span of UTF-encoded characters out of internal buffer
3185          * (starting at offset pos and ending at or before offset end),
3186          * consuming no more than utflen bytes.  Appends read characters to
3187          * sbuf.  Returns the number of bytes consumed.
3188          */
3189         private long readUTFSpan(StringBuilder sbuf, long utflen)
3190             throws IOException
3191         {
3192             int cpos = 0;
3193             int start = pos;
3194             int avail = Math.min(end - pos, CHAR_BUF_SIZE);
3195             // stop short of last char unless all of utf bytes in buffer
3196             int stop = pos + ((utflen > avail) ? avail - 2 : (int) utflen);
3197             boolean outOfBounds = false;
3198 
3199             try {
3200                 while (pos < stop) {
3201                     int b1, b2, b3;
3202                     b1 = buf[pos++] & 0xFF;
3203                     switch (b1 >> 4) {
3204                         case 0:
3205                         case 1:
3206                         case 2:
3207                         case 3:
3208                         case 4:
3209                         case 5:
3210                         case 6:
3211                         case 7:   // 1 byte format: 0xxxxxxx
3212                             cbuf[cpos++] = (char) b1;
3213                             break;
3214 
3215                         case 12:
3216                         case 13:  // 2 byte format: 110xxxxx 10xxxxxx
3217                             b2 = buf[pos++];
3218                             if ((b2 & 0xC0) != 0x80) {
3219                                 throw new UTFDataFormatException();
3220                             }
3221                             cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) |
3222                                                    ((b2 & 0x3F) << 0));
3223                             break;
3224 
3225                         case 14:  // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3226                             b3 = buf[pos + 1];
3227                             b2 = buf[pos + 0];
3228                             pos += 2;
3229                             if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3230                                 throw new UTFDataFormatException();
3231                             }
3232                             cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) |
3233                                                    ((b2 & 0x3F) << 6) |
3234                                                    ((b3 & 0x3F) << 0));
3235                             break;
3236 
3237                         default:  // 10xx xxxx, 1111 xxxx
3238                             throw new UTFDataFormatException();
3239                     }
3240                 }
3241             } catch (ArrayIndexOutOfBoundsException ex) {
3242                 outOfBounds = true;
3243             } finally {
3244                 if (outOfBounds || (pos - start) > utflen) {
3245                     /*
3246                      * Fix for 4450867: if a malformed utf char causes the
3247                      * conversion loop to scan past the expected end of the utf
3248                      * string, only consume the expected number of utf bytes.
3249                      */
3250                     pos = start + (int) utflen;
3251                     throw new UTFDataFormatException();
3252                 }
3253             }
3254 
3255             sbuf.append(cbuf, 0, cpos);
3256             return pos - start;
3257         }
3258 
3259         /**
3260          * Reads in single UTF-encoded character one byte at a time, appends
3261          * the character to sbuf, and returns the number of bytes consumed.
3262          * This method is used when reading in UTF strings written in block
3263          * data mode to handle UTF-encoded characters which (potentially)
3264          * straddle block-data boundaries.
3265          */
3266         private int readUTFChar(StringBuilder sbuf, long utflen)
3267             throws IOException
3268         {
3269             int b1, b2, b3;
3270             b1 = readByte() & 0xFF;
3271             switch (b1 >> 4) {
3272                 case 0:
3273                 case 1:
3274                 case 2:
3275                 case 3:
3276                 case 4:
3277                 case 5:
3278                 case 6:
3279                 case 7:     // 1 byte format: 0xxxxxxx
3280                     sbuf.append((char) b1);
3281                     return 1;
3282 
3283                 case 12:
3284                 case 13:    // 2 byte format: 110xxxxx 10xxxxxx
3285                     if (utflen < 2) {
3286                         throw new UTFDataFormatException();
3287                     }
3288                     b2 = readByte();
3289                     if ((b2 & 0xC0) != 0x80) {
3290                         throw new UTFDataFormatException();
3291                     }
3292                     sbuf.append((char) (((b1 & 0x1F) << 6) |
3293                                         ((b2 & 0x3F) << 0)));
3294                     return 2;
3295 
3296                 case 14:    // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3297                     if (utflen < 3) {
3298                         if (utflen == 2) {
3299                             readByte();         // consume remaining byte
3300                         }
3301                         throw new UTFDataFormatException();
3302                     }
3303                     b2 = readByte();
3304                     b3 = readByte();
3305                     if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3306                         throw new UTFDataFormatException();
3307                     }
3308                     sbuf.append((char) (((b1 & 0x0F) << 12) |
3309                                         ((b2 & 0x3F) << 6) |
3310                                         ((b3 & 0x3F) << 0)));
3311                     return 3;
3312 
3313                 default:   // 10xx xxxx, 1111 xxxx
3314                     throw new UTFDataFormatException();
3315             }
3316         }
3317     }
3318 
3319     /**
3320      * Unsynchronized table which tracks wire handle to object mappings, as
3321      * well as ClassNotFoundExceptions associated with deserialized objects.
3322      * This class implements an exception-propagation algorithm for
3323      * determining which objects should have ClassNotFoundExceptions associated
3324      * with them, taking into account cycles and discontinuities (e.g., skipped
3325      * fields) in the object graph.
3326      *
3327      * <p>General use of the table is as follows: during deserialization, a
3328      * given object is first assigned a handle by calling the assign method.
3329      * This method leaves the assigned handle in an "open" state, wherein
3330      * dependencies on the exception status of other handles can be registered
3331      * by calling the markDependency method, or an exception can be directly
3332      * associated with the handle by calling markException.  When a handle is
3333      * tagged with an exception, the HandleTable assumes responsibility for
3334      * propagating the exception to any other objects which depend
3335      * (transitively) on the exception-tagged object.
3336      *
3337      * <p>Once all exception information/dependencies for the handle have been
3338      * registered, the handle should be "closed" by calling the finish method
3339      * on it.  The act of finishing a handle allows the exception propagation
3340      * algorithm to aggressively prune dependency links, lessening the
3341      * performance/memory impact of exception tracking.
3342      *
3343      * <p>Note that the exception propagation algorithm used depends on handles
3344      * being assigned/finished in LIFO order; however, for simplicity as well
3345      * as memory conservation, it does not enforce this constraint.
3346      */
3347     // REMIND: add full description of exception propagation algorithm?
3348     private static class HandleTable {
3349 
3350         /* status codes indicating whether object has associated exception */
3351         private static final byte STATUS_OK = 1;
3352         private static final byte STATUS_UNKNOWN = 2;
3353         private static final byte STATUS_EXCEPTION = 3;
3354 
3355         /** array mapping handle -> object status */
3356         byte[] status;
3357         /** array mapping handle -> object/exception (depending on status) */
3358         Object[] entries;
3359         /** array mapping handle -> list of dependent handles (if any) */
3360         HandleList[] deps;
3361         /** lowest unresolved dependency */
3362         int lowDep = -1;
3363         /** number of handles in table */
3364         int size = 0;
3365 
3366         /**
3367          * Creates handle table with the given initial capacity.
3368          */
3369         HandleTable(int initialCapacity) {
3370             status = new byte[initialCapacity];
3371             entries = new Object[initialCapacity];
3372             deps = new HandleList[initialCapacity];
3373         }
3374 
3375         /**
3376          * Assigns next available handle to given object, and returns assigned
3377          * handle.  Once object has been completely deserialized (and all
3378          * dependencies on other objects identified), the handle should be
3379          * "closed" by passing it to finish().
3380          */
3381         int assign(Object obj) {
3382             if (size >= entries.length) {
3383                 grow();
3384             }
3385             status[size] = STATUS_UNKNOWN;
3386             entries[size] = obj;
3387             return size++;
3388         }
3389 
3390         /**
3391          * Registers a dependency (in exception status) of one handle on
3392          * another.  The dependent handle must be "open" (i.e., assigned, but
3393          * not finished yet).  No action is taken if either dependent or target
3394          * handle is NULL_HANDLE. Additionally, no action is taken if the
3395          * dependent and target are the same.
3396          */
3397         void markDependency(int dependent, int target) {
3398             if (dependent == target || dependent == NULL_HANDLE || target == NULL_HANDLE) {
3399                 return;
3400             }
3401             switch (status[dependent]) {
3402 
3403                 case STATUS_UNKNOWN:
3404                     switch (status[target]) {
3405                         case STATUS_OK:
3406                             // ignore dependencies on objs with no exception
3407                             break;
3408 
3409                         case STATUS_EXCEPTION:
3410                             // eagerly propagate exception
3411                             markException(dependent,
3412                                 (ClassNotFoundException) entries[target]);
3413                             break;
3414 
3415                         case STATUS_UNKNOWN:
3416                             // add to dependency list of target
3417                             if (deps[target] == null) {
3418                                 deps[target] = new HandleList();
3419                             }
3420                             deps[target].add(dependent);
3421 
3422                             // remember lowest unresolved target seen
3423                             if (lowDep < 0 || lowDep > target) {
3424                                 lowDep = target;
3425                             }
3426                             break;
3427 
3428                         default:
3429                             throw new InternalError();
3430                     }
3431                     break;
3432 
3433                 case STATUS_EXCEPTION:
3434                     break;
3435 
3436                 default:
3437                     throw new InternalError();
3438             }
3439         }
3440 
3441         /**
3442          * Associates a ClassNotFoundException (if one not already associated)
3443          * with the currently active handle and propagates it to other
3444          * referencing objects as appropriate.  The specified handle must be
3445          * "open" (i.e., assigned, but not finished yet).
3446          */
3447         void markException(int handle, ClassNotFoundException ex) {
3448             switch (status[handle]) {
3449                 case STATUS_UNKNOWN:
3450                     status[handle] = STATUS_EXCEPTION;
3451                     entries[handle] = ex;
3452 
3453                     // propagate exception to dependents
3454                     HandleList dlist = deps[handle];
3455                     if (dlist != null) {
3456                         int ndeps = dlist.size();
3457                         for (int i = 0; i < ndeps; i++) {
3458                             markException(dlist.get(i), ex);
3459                         }
3460                         deps[handle] = null;
3461                     }
3462                     break;
3463 
3464                 case STATUS_EXCEPTION:
3465                     break;
3466 
3467                 default:
3468                     throw new InternalError();
3469             }
3470         }
3471 
3472         /**
3473          * Marks given handle as finished, meaning that no new dependencies
3474          * will be marked for handle.  Calls to the assign and finish methods
3475          * must occur in LIFO order.
3476          */
3477         void finish(int handle) {
3478             int end;
3479             if (lowDep < 0) {
3480                 // no pending unknowns, only resolve current handle
3481                 end = handle + 1;
3482             } else if (lowDep >= handle) {
3483                 // pending unknowns now clearable, resolve all upward handles
3484                 end = size;
3485                 lowDep = -1;
3486             } else {
3487                 // unresolved backrefs present, can't resolve anything yet
3488                 return;
3489             }
3490 
3491             // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
3492             for (int i = handle; i < end; i++) {
3493                 switch (status[i]) {
3494                     case STATUS_UNKNOWN:
3495                         status[i] = STATUS_OK;
3496                         deps[i] = null;
3497                         break;
3498 
3499                     case STATUS_OK:
3500                     case STATUS_EXCEPTION:
3501                         break;
3502 
3503                     default:
3504                         throw new InternalError();
3505                 }
3506             }
3507         }
3508 
3509         /**
3510          * Assigns a new object to the given handle.  The object previously
3511          * associated with the handle is forgotten.  This method has no effect
3512          * if the given handle already has an exception associated with it.
3513          * This method may be called at any time after the handle is assigned.
3514          */
3515         void setObject(int handle, Object obj) {
3516             switch (status[handle]) {
3517                 case STATUS_UNKNOWN:
3518                 case STATUS_OK:
3519                     entries[handle] = obj;
3520                     break;
3521 
3522                 case STATUS_EXCEPTION:
3523                     break;
3524 
3525                 default:
3526                     throw new InternalError();
3527             }
3528         }
3529 
3530         /**
3531          * Looks up and returns object associated with the given handle.
3532          * Returns null if the given handle is NULL_HANDLE, or if it has an
3533          * associated ClassNotFoundException.
3534          */
3535         Object lookupObject(int handle) {
3536             return (handle != NULL_HANDLE &&
3537                     status[handle] != STATUS_EXCEPTION) ?
3538                 entries[handle] : null;
3539         }
3540 
3541         /**
3542          * Looks up and returns ClassNotFoundException associated with the
3543          * given handle.  Returns null if the given handle is NULL_HANDLE, or
3544          * if there is no ClassNotFoundException associated with the handle.
3545          */
3546         ClassNotFoundException lookupException(int handle) {
3547             return (handle != NULL_HANDLE &&
3548                     status[handle] == STATUS_EXCEPTION) ?
3549                 (ClassNotFoundException) entries[handle] : null;
3550         }
3551 
3552         /**
3553          * Resets table to its initial state.
3554          */
3555         void clear() {
3556             Arrays.fill(status, 0, size, (byte) 0);
3557             Arrays.fill(entries, 0, size, null);
3558             Arrays.fill(deps, 0, size, null);
3559             lowDep = -1;
3560             size = 0;
3561         }
3562 
3563         /**
3564          * Returns number of handles registered in table.
3565          */
3566         int size() {
3567             return size;
3568         }
3569 
3570         /**
3571          * Expands capacity of internal arrays.
3572          */
3573         private void grow() {
3574             int newCapacity = (entries.length << 1) + 1;
3575 
3576             byte[] newStatus = new byte[newCapacity];
3577             Object[] newEntries = new Object[newCapacity];
3578             HandleList[] newDeps = new HandleList[newCapacity];
3579 
3580             System.arraycopy(status, 0, newStatus, 0, size);
3581             System.arraycopy(entries, 0, newEntries, 0, size);
3582             System.arraycopy(deps, 0, newDeps, 0, size);
3583 
3584             status = newStatus;
3585             entries = newEntries;
3586             deps = newDeps;
3587         }
3588 
3589         /**
3590          * Simple growable list of (integer) handles.
3591          */
3592         private static class HandleList {
3593             private int[] list = new int[4];
3594             private int size = 0;
3595 
3596             public HandleList() {
3597             }
3598 
3599             public void add(int handle) {
3600                 if (size >= list.length) {
3601                     int[] newList = new int[list.length << 1];
3602                     System.arraycopy(list, 0, newList, 0, list.length);
3603                     list = newList;
3604                 }
3605                 list[size++] = handle;
3606             }
3607 
3608             public int get(int index) {
3609                 if (index >= size) {
3610                     throw new ArrayIndexOutOfBoundsException();
3611                 }
3612                 return list[index];
3613             }
3614 
3615             public int size() {
3616                 return size;
3617             }
3618         }
3619     }
3620 
3621     /**
3622      * Method for cloning arrays in case of using unsharing reading
3623      */
3624     private static Object cloneArray(Object array) {
3625         if (array instanceof Object[]) {
3626             return ((Object[]) array).clone();
3627         } else if (array instanceof boolean[]) {
3628             return ((boolean[]) array).clone();
3629         } else if (array instanceof byte[]) {
3630             return ((byte[]) array).clone();
3631         } else if (array instanceof char[]) {
3632             return ((char[]) array).clone();
3633         } else if (array instanceof double[]) {
3634             return ((double[]) array).clone();
3635         } else if (array instanceof float[]) {
3636             return ((float[]) array).clone();
3637         } else if (array instanceof int[]) {
3638             return ((int[]) array).clone();
3639         } else if (array instanceof long[]) {
3640             return ((long[]) array).clone();
3641         } else if (array instanceof short[]) {
3642             return ((short[]) array).clone();
3643         } else {
3644             throw new AssertionError();
3645         }
3646     }
3647 
3648 }