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