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