1 /*
   2  * Copyright (c) 1996, 2019, 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.lang.ref.Reference;
  29 import java.lang.ref.ReferenceQueue;
  30 import java.lang.ref.SoftReference;
  31 import java.lang.ref.WeakReference;
  32 import java.lang.reflect.Constructor;
  33 import java.lang.reflect.Field;
  34 import java.lang.reflect.InvocationTargetException;
  35 import java.lang.reflect.UndeclaredThrowableException;
  36 import java.lang.reflect.Member;
  37 import java.lang.reflect.Method;
  38 import java.lang.reflect.Modifier;
  39 import java.lang.reflect.Proxy;
  40 import java.security.AccessControlContext;
  41 import java.security.AccessController;
  42 import java.security.MessageDigest;
  43 import java.security.NoSuchAlgorithmException;
  44 import java.security.PermissionCollection;
  45 import java.security.Permissions;
  46 import java.security.PrivilegedAction;
  47 import java.security.ProtectionDomain;
  48 import java.util.ArrayList;
  49 import java.util.Arrays;
  50 import java.util.Collections;
  51 import java.util.Comparator;
  52 import java.util.HashSet;
  53 import java.util.Set;
  54 import java.util.concurrent.ConcurrentHashMap;
  55 import java.util.concurrent.ConcurrentMap;
  56 import jdk.internal.misc.Unsafe;
  57 import jdk.internal.reflect.CallerSensitive;
  58 import jdk.internal.reflect.Reflection;
  59 import jdk.internal.reflect.ReflectionFactory;
  60 import jdk.internal.access.SharedSecrets;
  61 import jdk.internal.access.JavaSecurityAccess;
  62 import sun.reflect.misc.ReflectUtil;
  63 import static java.io.ObjectStreamField.*;
  64 
  65 /**
  66  * Serialization's descriptor for classes.  It contains the name and
  67  * serialVersionUID of the class.  The ObjectStreamClass for a specific class
  68  * loaded in this Java VM can be found/created using the lookup method.
  69  *
  70  * <p>The algorithm to compute the SerialVersionUID is described in
  71  * <a href="{@docRoot}/../specs/serialization/class.html#stream-unique-identifiers">
  72  *     Object Serialization Specification, Section 4.6, Stream Unique Identifiers</a>.
  73  *
  74  * @author      Mike Warres
  75  * @author      Roger Riggs
  76  * @see ObjectStreamField
  77  * @see <a href="{@docRoot}/../specs/serialization/class.html">
  78  *     Object Serialization Specification, Section 4, Class Descriptors</a>
  79  * @since   1.1
  80  */
  81 public class ObjectStreamClass implements Serializable {
  82 
  83     /** serialPersistentFields value indicating no serializable fields */
  84     public static final ObjectStreamField[] NO_FIELDS =
  85         new ObjectStreamField[0];
  86 
  87     @java.io.Serial
  88     private static final long serialVersionUID = -6120832682080437368L;
  89     @java.io.Serial
  90     private static final ObjectStreamField[] serialPersistentFields =
  91         NO_FIELDS;
  92 
  93     /** reflection factory for obtaining serialization constructors */
  94     private static final ReflectionFactory reflFactory =
  95         AccessController.doPrivileged(
  96             new ReflectionFactory.GetReflectionFactoryAction());
  97 
  98     private static class Caches {
  99         /** cache mapping local classes -> descriptors */
 100         static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs =
 101             new ConcurrentHashMap<>();
 102 
 103         /** cache mapping field group/local desc pairs -> field reflectors */
 104         static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors =
 105             new ConcurrentHashMap<>();
 106 
 107         /** queue for WeakReferences to local classes */
 108         private static final ReferenceQueue<Class<?>> localDescsQueue =
 109             new ReferenceQueue<>();
 110         /** queue for WeakReferences to field reflectors keys */
 111         private static final ReferenceQueue<Class<?>> reflectorsQueue =
 112             new ReferenceQueue<>();
 113     }
 114 
 115     /** class associated with this descriptor (if any) */
 116     private Class<?> cl;
 117     /** name of class represented by this descriptor */
 118     private String name;
 119     /** serialVersionUID of represented class (null if not computed yet) */
 120     private volatile Long suid;
 121 
 122     /** true if represents dynamic proxy class */
 123     private boolean isProxy;
 124     /** true if represents enum type */
 125     private boolean isEnum;
 126     /** true if represented class implements Serializable */
 127     private boolean serializable;
 128     /** true if represented class implements Externalizable */
 129     private boolean externalizable;
 130     /** true if desc has data written by class-defined writeObject method */
 131     private boolean hasWriteObjectData;
 132     /**
 133      * true if desc has externalizable data written in block data format; this
 134      * must be true by default to accommodate ObjectInputStream subclasses which
 135      * override readClassDescriptor() to return class descriptors obtained from
 136      * ObjectStreamClass.lookup() (see 4461737)
 137      */
 138     private boolean hasBlockExternalData = true;
 139 
 140     /**
 141      * Contains information about InvalidClassException instances to be thrown
 142      * when attempting operations on an invalid class. Note that instances of
 143      * this class are immutable and are potentially shared among
 144      * ObjectStreamClass instances.
 145      */
 146     private static class ExceptionInfo {
 147         private final String className;
 148         private final String message;
 149 
 150         ExceptionInfo(String cn, String msg) {
 151             className = cn;
 152             message = msg;
 153         }
 154 
 155         /**
 156          * Returns (does not throw) an InvalidClassException instance created
 157          * from the information in this object, suitable for being thrown by
 158          * the caller.
 159          */
 160         InvalidClassException newInvalidClassException() {
 161             return new InvalidClassException(className, message);
 162         }
 163     }
 164 
 165     /** exception (if any) thrown while attempting to resolve class */
 166     private ClassNotFoundException resolveEx;
 167     /** exception (if any) to throw if non-enum deserialization attempted */
 168     private ExceptionInfo deserializeEx;
 169     /** exception (if any) to throw if non-enum serialization attempted */
 170     private ExceptionInfo serializeEx;
 171     /** exception (if any) to throw if default serialization attempted */
 172     private ExceptionInfo defaultSerializeEx;
 173 
 174     /** serializable fields */
 175     private ObjectStreamField[] fields;
 176     /** aggregate marshalled size of primitive fields */
 177     private int primDataSize;
 178     /** number of non-primitive fields */
 179     private int numObjFields;
 180     /** reflector for setting/getting serializable field values */
 181     private FieldReflector fieldRefl;
 182     /** data layout of serialized objects described by this class desc */
 183     private volatile ClassDataSlot[] dataLayout;
 184 
 185     /** serialization-appropriate constructor, or null if none */
 186     private Constructor<?> cons;
 187     /** protection domains that need to be checked when calling the constructor */
 188     private ProtectionDomain[] domains;
 189 
 190     /** class-defined writeObject method, or null if none */
 191     private Method writeObjectMethod;
 192     /** class-defined readObject method, or null if none */
 193     private Method readObjectMethod;
 194     /** class-defined readObjectNoData method, or null if none */
 195     private Method readObjectNoDataMethod;
 196     /** class-defined writeReplace method, or null if none */
 197     private Method writeReplaceMethod;
 198     /** class-defined readResolve method, or null if none */
 199     private Method readResolveMethod;
 200 
 201     /** local class descriptor for represented class (may point to self) */
 202     private ObjectStreamClass localDesc;
 203     /** superclass descriptor appearing in stream */
 204     private ObjectStreamClass superDesc;
 205 
 206     /** true if, and only if, the object has been correctly initialized */
 207     private boolean initialized;
 208 
 209     /**
 210      * Initializes native code.
 211      */
 212     private static native void initNative();
 213     static {
 214         initNative();
 215     }
 216 
 217     /**
 218      * Find the descriptor for a class that can be serialized.  Creates an
 219      * ObjectStreamClass instance if one does not exist yet for class. Null is
 220      * returned if the specified class does not implement java.io.Serializable
 221      * or java.io.Externalizable.
 222      *
 223      * @param   cl class for which to get the descriptor
 224      * @return  the class descriptor for the specified class
 225      */
 226     public static ObjectStreamClass lookup(Class<?> cl) {
 227         return lookup(cl, false);
 228     }
 229 
 230     /**
 231      * Returns the descriptor for any class, regardless of whether it
 232      * implements {@link Serializable}.
 233      *
 234      * @param        cl class for which to get the descriptor
 235      * @return       the class descriptor for the specified class
 236      * @since 1.6
 237      */
 238     public static ObjectStreamClass lookupAny(Class<?> cl) {
 239         return lookup(cl, true);
 240     }
 241 
 242     /**
 243      * Returns the name of the class described by this descriptor.
 244      * This method returns the name of the class in the format that
 245      * is used by the {@link Class#getName} method.
 246      *
 247      * @return a string representing the name of the class
 248      */
 249     public String getName() {
 250         return name;
 251     }
 252 
 253     /**
 254      * Return the serialVersionUID for this class.  The serialVersionUID
 255      * defines a set of classes all with the same name that have evolved from a
 256      * common root class and agree to be serialized and deserialized using a
 257      * common format.  NonSerializable classes have a serialVersionUID of 0L.
 258      *
 259      * @return  the SUID of the class described by this descriptor
 260      */
 261     public long getSerialVersionUID() {
 262         // REMIND: synchronize instead of relying on volatile?
 263         if (suid == null) {
 264             suid = AccessController.doPrivileged(
 265                 new PrivilegedAction<Long>() {
 266                     public Long run() {
 267                         return computeDefaultSUID(cl);
 268                     }
 269                 }
 270             );
 271         }
 272         return suid.longValue();
 273     }
 274 
 275     /**
 276      * Return the class in the local VM that this version is mapped to.  Null
 277      * is returned if there is no corresponding local class.
 278      *
 279      * @return  the <code>Class</code> instance that this descriptor represents
 280      */
 281     @CallerSensitive
 282     public Class<?> forClass() {
 283         if (cl == null) {
 284             return null;
 285         }
 286         requireInitialized();
 287         if (System.getSecurityManager() != null) {
 288             Class<?> caller = Reflection.getCallerClass();
 289             if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) {
 290                 ReflectUtil.checkPackageAccess(cl);
 291             }
 292         }
 293         return cl;
 294     }
 295 
 296     /**
 297      * Return an array of the fields of this serializable class.
 298      *
 299      * @return  an array containing an element for each persistent field of
 300      *          this class. Returns an array of length zero if there are no
 301      *          fields.
 302      * @since 1.2
 303      */
 304     public ObjectStreamField[] getFields() {
 305         return getFields(true);
 306     }
 307 
 308     /**
 309      * Get the field of this class by name.
 310      *
 311      * @param   name the name of the data field to look for
 312      * @return  The ObjectStreamField object of the named field or null if
 313      *          there is no such named field.
 314      */
 315     public ObjectStreamField getField(String name) {
 316         return getField(name, null);
 317     }
 318 
 319     /**
 320      * Return a string describing this ObjectStreamClass.
 321      */
 322     public String toString() {
 323         return name + ": static final long serialVersionUID = " +
 324             getSerialVersionUID() + "L;";
 325     }
 326 
 327     /**
 328      * Looks up and returns class descriptor for given class, or null if class
 329      * is non-serializable and "all" is set to false.
 330      *
 331      * @param   cl class to look up
 332      * @param   all if true, return descriptors for all classes; if false, only
 333      *          return descriptors for serializable classes
 334      */
 335     static ObjectStreamClass lookup(Class<?> cl, boolean all) {
 336         if (!(all || Serializable.class.isAssignableFrom(cl))) {
 337             return null;
 338         }
 339         processQueue(Caches.localDescsQueue, Caches.localDescs);
 340         WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
 341         Reference<?> ref = Caches.localDescs.get(key);
 342         Object entry = null;
 343         if (ref != null) {
 344             entry = ref.get();
 345         }
 346         EntryFuture future = null;
 347         if (entry == null) {
 348             EntryFuture newEntry = new EntryFuture();
 349             Reference<?> newRef = new SoftReference<>(newEntry);
 350             do {
 351                 if (ref != null) {
 352                     Caches.localDescs.remove(key, ref);
 353                 }
 354                 ref = Caches.localDescs.putIfAbsent(key, newRef);
 355                 if (ref != null) {
 356                     entry = ref.get();
 357                 }
 358             } while (ref != null && entry == null);
 359             if (entry == null) {
 360                 future = newEntry;
 361             }
 362         }
 363 
 364         if (entry instanceof ObjectStreamClass) {  // check common case first
 365             return (ObjectStreamClass) entry;
 366         }
 367         if (entry instanceof EntryFuture) {
 368             future = (EntryFuture) entry;
 369             if (future.getOwner() == Thread.currentThread()) {
 370                 /*
 371                  * Handle nested call situation described by 4803747: waiting
 372                  * for future value to be set by a lookup() call further up the
 373                  * stack will result in deadlock, so calculate and set the
 374                  * future value here instead.
 375                  */
 376                 entry = null;
 377             } else {
 378                 entry = future.get();
 379             }
 380         }
 381         if (entry == null) {
 382             try {
 383                 entry = new ObjectStreamClass(cl);
 384             } catch (Throwable th) {
 385                 entry = th;
 386             }
 387             if (future.set(entry)) {
 388                 Caches.localDescs.put(key, new SoftReference<>(entry));
 389             } else {
 390                 // nested lookup call already set future
 391                 entry = future.get();
 392             }
 393         }
 394 
 395         if (entry instanceof ObjectStreamClass) {
 396             return (ObjectStreamClass) entry;
 397         } else if (entry instanceof RuntimeException) {
 398             throw (RuntimeException) entry;
 399         } else if (entry instanceof Error) {
 400             throw (Error) entry;
 401         } else {
 402             throw new InternalError("unexpected entry: " + entry);
 403         }
 404     }
 405 
 406     /**
 407      * Placeholder used in class descriptor and field reflector lookup tables
 408      * for an entry in the process of being initialized.  (Internal) callers
 409      * which receive an EntryFuture belonging to another thread as the result
 410      * of a lookup should call the get() method of the EntryFuture; this will
 411      * return the actual entry once it is ready for use and has been set().  To
 412      * conserve objects, EntryFutures synchronize on themselves.
 413      */
 414     private static class EntryFuture {
 415 
 416         private static final Object unset = new Object();
 417         private final Thread owner = Thread.currentThread();
 418         private Object entry = unset;
 419 
 420         /**
 421          * Attempts to set the value contained by this EntryFuture.  If the
 422          * EntryFuture's value has not been set already, then the value is
 423          * saved, any callers blocked in the get() method are notified, and
 424          * true is returned.  If the value has already been set, then no saving
 425          * or notification occurs, and false is returned.
 426          */
 427         synchronized boolean set(Object entry) {
 428             if (this.entry != unset) {
 429                 return false;
 430             }
 431             this.entry = entry;
 432             notifyAll();
 433             return true;
 434         }
 435 
 436         /**
 437          * Returns the value contained by this EntryFuture, blocking if
 438          * necessary until a value is set.
 439          */
 440         synchronized Object get() {
 441             boolean interrupted = false;
 442             while (entry == unset) {
 443                 try {
 444                     wait();
 445                 } catch (InterruptedException ex) {
 446                     interrupted = true;
 447                 }
 448             }
 449             if (interrupted) {
 450                 AccessController.doPrivileged(
 451                     new PrivilegedAction<>() {
 452                         public Void run() {
 453                             Thread.currentThread().interrupt();
 454                             return null;
 455                         }
 456                     }
 457                 );
 458             }
 459             return entry;
 460         }
 461 
 462         /**
 463          * Returns the thread that created this EntryFuture.
 464          */
 465         Thread getOwner() {
 466             return owner;
 467         }
 468     }
 469 
 470     /**
 471      * Creates local class descriptor representing given class.
 472      */
 473     private ObjectStreamClass(final Class<?> cl) {
 474         this.cl = cl;
 475         name = cl.getName();
 476         isProxy = Proxy.isProxyClass(cl);
 477         isEnum = Enum.class.isAssignableFrom(cl);
 478         serializable = Serializable.class.isAssignableFrom(cl);
 479         externalizable = Externalizable.class.isAssignableFrom(cl);
 480 
 481         Class<?> superCl = cl.getSuperclass();
 482         superDesc = (superCl != null) ? lookup(superCl, false) : null;
 483         localDesc = this;
 484 
 485         if (serializable) {
 486             AccessController.doPrivileged(new PrivilegedAction<>() {
 487                 public Void run() {
 488                     if (isEnum) {
 489                         suid = Long.valueOf(0);
 490                         fields = NO_FIELDS;
 491                         return null;
 492                     }
 493                     if (cl.isArray()) {
 494                         fields = NO_FIELDS;
 495                         return null;
 496                     }
 497 
 498                     suid = getDeclaredSUID(cl);
 499                     try {
 500                         fields = getSerialFields(cl);
 501                         computeFieldOffsets();
 502                     } catch (InvalidClassException e) {
 503                         serializeEx = deserializeEx =
 504                             new ExceptionInfo(e.classname, e.getMessage());
 505                         fields = NO_FIELDS;
 506                     }
 507 
 508                     if (externalizable) {
 509                         cons = getExternalizableConstructor(cl);
 510                     } else {
 511                         cons = getSerializableConstructor(cl);
 512                         writeObjectMethod = getPrivateMethod(cl, "writeObject",
 513                             new Class<?>[] { ObjectOutputStream.class },
 514                             Void.TYPE);
 515                         readObjectMethod = getPrivateMethod(cl, "readObject",
 516                             new Class<?>[] { ObjectInputStream.class },
 517                             Void.TYPE);
 518                         readObjectNoDataMethod = getPrivateMethod(
 519                             cl, "readObjectNoData", null, Void.TYPE);
 520                         hasWriteObjectData = (writeObjectMethod != null);
 521                     }
 522                     domains = getProtectionDomains(cons, cl);
 523                     writeReplaceMethod = getInheritableMethod(
 524                         cl, "writeReplace", null, Object.class);
 525                     readResolveMethod = getInheritableMethod(
 526                         cl, "readResolve", null, Object.class);
 527                     return null;
 528                 }
 529             });
 530         } else {
 531             suid = Long.valueOf(0);
 532             fields = NO_FIELDS;
 533         }
 534 
 535         try {
 536             fieldRefl = getReflector(fields, this);
 537         } catch (InvalidClassException ex) {
 538             // field mismatches impossible when matching local fields vs. self
 539             throw new InternalError(ex);
 540         }
 541 
 542         if (deserializeEx == null) {
 543             if (isEnum) {
 544                 deserializeEx = new ExceptionInfo(name, "enum type");
 545             } else if (cons == null) {
 546                 deserializeEx = new ExceptionInfo(name, "no valid constructor");
 547             }
 548         }
 549         for (int i = 0; i < fields.length; i++) {
 550             if (fields[i].getField() == null) {
 551                 defaultSerializeEx = new ExceptionInfo(
 552                     name, "unmatched serializable field(s) declared");
 553             }
 554         }
 555         initialized = true;
 556     }
 557 
 558     /**
 559      * Creates blank class descriptor which should be initialized via a
 560      * subsequent call to initProxy(), initNonProxy() or readNonProxy().
 561      */
 562     ObjectStreamClass() {
 563     }
 564 
 565     /**
 566      * Creates a PermissionDomain that grants no permission.
 567      */
 568     private ProtectionDomain noPermissionsDomain() {
 569         PermissionCollection perms = new Permissions();
 570         perms.setReadOnly();
 571         return new ProtectionDomain(null, perms);
 572     }
 573 
 574     /**
 575      * Aggregate the ProtectionDomains of all the classes that separate
 576      * a concrete class {@code cl} from its ancestor's class declaring
 577      * a constructor {@code cons}.
 578      *
 579      * If {@code cl} is defined by the boot loader, or the constructor
 580      * {@code cons} is declared by {@code cl}, or if there is no security
 581      * manager, then this method does nothing and {@code null} is returned.
 582      *
 583      * @param cons A constructor declared by {@code cl} or one of its
 584      *             ancestors.
 585      * @param cl A concrete class, which is either the class declaring
 586      *           the constructor {@code cons}, or a serializable subclass
 587      *           of that class.
 588      * @return An array of ProtectionDomain representing the set of
 589      *         ProtectionDomain that separate the concrete class {@code cl}
 590      *         from its ancestor's declaring {@code cons}, or {@code null}.
 591      */
 592     private ProtectionDomain[] getProtectionDomains(Constructor<?> cons,
 593                                                     Class<?> cl) {
 594         ProtectionDomain[] domains = null;
 595         if (cons != null && cl.getClassLoader() != null
 596                 && System.getSecurityManager() != null) {
 597             Class<?> cls = cl;
 598             Class<?> fnscl = cons.getDeclaringClass();
 599             Set<ProtectionDomain> pds = null;
 600             while (cls != fnscl) {
 601                 ProtectionDomain pd = cls.getProtectionDomain();
 602                 if (pd != null) {
 603                     if (pds == null) pds = new HashSet<>();
 604                     pds.add(pd);
 605                 }
 606                 cls = cls.getSuperclass();
 607                 if (cls == null) {
 608                     // that's not supposed to happen
 609                     // make a ProtectionDomain with no permission.
 610                     // should we throw instead?
 611                     if (pds == null) pds = new HashSet<>();
 612                     else pds.clear();
 613                     pds.add(noPermissionsDomain());
 614                     break;
 615                 }
 616             }
 617             if (pds != null) {
 618                 domains = pds.toArray(new ProtectionDomain[0]);
 619             }
 620         }
 621         return domains;
 622     }
 623 
 624     /**
 625      * Initializes class descriptor representing a proxy class.
 626      */
 627     void initProxy(Class<?> cl,
 628                    ClassNotFoundException resolveEx,
 629                    ObjectStreamClass superDesc)
 630         throws InvalidClassException
 631     {
 632         ObjectStreamClass osc = null;
 633         if (cl != null) {
 634             osc = lookup(cl, true);
 635             if (!osc.isProxy) {
 636                 throw new InvalidClassException(
 637                     "cannot bind proxy descriptor to a non-proxy class");
 638             }
 639         }
 640         this.cl = cl;
 641         this.resolveEx = resolveEx;
 642         this.superDesc = superDesc;
 643         isProxy = true;
 644         serializable = true;
 645         suid = Long.valueOf(0);
 646         fields = NO_FIELDS;
 647         if (osc != null) {
 648             localDesc = osc;
 649             name = localDesc.name;
 650             externalizable = localDesc.externalizable;
 651             writeReplaceMethod = localDesc.writeReplaceMethod;
 652             readResolveMethod = localDesc.readResolveMethod;
 653             deserializeEx = localDesc.deserializeEx;
 654             domains = localDesc.domains;
 655             cons = localDesc.cons;
 656         }
 657         fieldRefl = getReflector(fields, localDesc);
 658         initialized = true;
 659     }
 660 
 661     /**
 662      * Initializes class descriptor representing a non-proxy class.
 663      */
 664     void initNonProxy(ObjectStreamClass model,
 665                       Class<?> cl,
 666                       ClassNotFoundException resolveEx,
 667                       ObjectStreamClass superDesc)
 668         throws InvalidClassException
 669     {
 670         long suid = Long.valueOf(model.getSerialVersionUID());
 671         ObjectStreamClass osc = null;
 672         if (cl != null) {
 673             osc = lookup(cl, true);
 674             if (osc.isProxy) {
 675                 throw new InvalidClassException(
 676                         "cannot bind non-proxy descriptor to a proxy class");
 677             }
 678             if (model.isEnum != osc.isEnum) {
 679                 throw new InvalidClassException(model.isEnum ?
 680                         "cannot bind enum descriptor to a non-enum class" :
 681                         "cannot bind non-enum descriptor to an enum class");
 682             }
 683 
 684             if (model.serializable == osc.serializable &&
 685                     !cl.isArray() &&
 686                     suid != osc.getSerialVersionUID()) {
 687                 throw new InvalidClassException(osc.name,
 688                         "local class incompatible: " +
 689                                 "stream classdesc serialVersionUID = " + suid +
 690                                 ", local class serialVersionUID = " +
 691                                 osc.getSerialVersionUID());
 692             }
 693 
 694             if (!classNamesEqual(model.name, osc.name)) {
 695                 throw new InvalidClassException(osc.name,
 696                         "local class name incompatible with stream class " +
 697                                 "name \"" + model.name + "\"");
 698             }
 699 
 700             if (!model.isEnum) {
 701                 if ((model.serializable == osc.serializable) &&
 702                         (model.externalizable != osc.externalizable)) {
 703                     throw new InvalidClassException(osc.name,
 704                             "Serializable incompatible with Externalizable");
 705                 }
 706 
 707                 if ((model.serializable != osc.serializable) ||
 708                         (model.externalizable != osc.externalizable) ||
 709                         !(model.serializable || model.externalizable)) {
 710                     deserializeEx = new ExceptionInfo(
 711                             osc.name, "class invalid for deserialization");
 712                 }
 713             }
 714         }
 715 
 716         this.cl = cl;
 717         this.resolveEx = resolveEx;
 718         this.superDesc = superDesc;
 719         name = model.name;
 720         this.suid = suid;
 721         isProxy = false;
 722         isEnum = model.isEnum;
 723         serializable = model.serializable;
 724         externalizable = model.externalizable;
 725         hasBlockExternalData = model.hasBlockExternalData;
 726         hasWriteObjectData = model.hasWriteObjectData;
 727         fields = model.fields;
 728         primDataSize = model.primDataSize;
 729         numObjFields = model.numObjFields;
 730 
 731         if (osc != null) {
 732             localDesc = osc;
 733             writeObjectMethod = localDesc.writeObjectMethod;
 734             readObjectMethod = localDesc.readObjectMethod;
 735             readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
 736             writeReplaceMethod = localDesc.writeReplaceMethod;
 737             readResolveMethod = localDesc.readResolveMethod;
 738             if (deserializeEx == null) {
 739                 deserializeEx = localDesc.deserializeEx;
 740             }
 741             domains = localDesc.domains;
 742             cons = localDesc.cons;
 743         }
 744 
 745         fieldRefl = getReflector(fields, localDesc);
 746         // reassign to matched fields so as to reflect local unshared settings
 747         fields = fieldRefl.getFields();
 748         initialized = true;
 749     }
 750 
 751     /**
 752      * Reads non-proxy class descriptor information from given input stream.
 753      * The resulting class descriptor is not fully functional; it can only be
 754      * used as input to the ObjectInputStream.resolveClass() and
 755      * ObjectStreamClass.initNonProxy() methods.
 756      */
 757     void readNonProxy(ObjectInputStream in)
 758         throws IOException, ClassNotFoundException
 759     {
 760         name = in.readUTF();
 761         suid = Long.valueOf(in.readLong());
 762         isProxy = false;
 763 
 764         byte flags = in.readByte();
 765         hasWriteObjectData =
 766             ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
 767         hasBlockExternalData =
 768             ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
 769         externalizable =
 770             ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
 771         boolean sflag =
 772             ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
 773         if (externalizable && sflag) {
 774             throw new InvalidClassException(
 775                 name, "serializable and externalizable flags conflict");
 776         }
 777         serializable = externalizable || sflag;
 778         isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
 779         if (isEnum && suid.longValue() != 0L) {
 780             throw new InvalidClassException(name,
 781                 "enum descriptor has non-zero serialVersionUID: " + suid);
 782         }
 783 
 784         int numFields = in.readShort();
 785         if (isEnum && numFields != 0) {
 786             throw new InvalidClassException(name,
 787                 "enum descriptor has non-zero field count: " + numFields);
 788         }
 789         fields = (numFields > 0) ?
 790             new ObjectStreamField[numFields] : NO_FIELDS;
 791         for (int i = 0; i < numFields; i++) {
 792             char tcode = (char) in.readByte();
 793             String fname = in.readUTF();
 794             String signature = ((tcode == 'L') || (tcode == '[')) ?
 795                 in.readTypeString() : new String(new char[] { tcode });
 796             try {
 797                 fields[i] = new ObjectStreamField(fname, signature, false);
 798             } catch (RuntimeException e) {
 799                 throw (IOException) new InvalidClassException(name,
 800                     "invalid descriptor for field " + fname).initCause(e);
 801             }
 802         }
 803         computeFieldOffsets();
 804     }
 805 
 806     /**
 807      * Writes non-proxy class descriptor information to given output stream.
 808      */
 809     void writeNonProxy(ObjectOutputStream out) throws IOException {
 810         out.writeUTF(name);
 811         out.writeLong(getSerialVersionUID());
 812 
 813         byte flags = 0;
 814         if (externalizable) {
 815             flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
 816             int protocol = out.getProtocolVersion();
 817             if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
 818                 flags |= ObjectStreamConstants.SC_BLOCK_DATA;
 819             }
 820         } else if (serializable) {
 821             flags |= ObjectStreamConstants.SC_SERIALIZABLE;
 822         }
 823         if (hasWriteObjectData) {
 824             flags |= ObjectStreamConstants.SC_WRITE_METHOD;
 825         }
 826         if (isEnum) {
 827             flags |= ObjectStreamConstants.SC_ENUM;
 828         }
 829         out.writeByte(flags);
 830 
 831         out.writeShort(fields.length);
 832         for (int i = 0; i < fields.length; i++) {
 833             ObjectStreamField f = fields[i];
 834             out.writeByte(f.getTypeCode());
 835             out.writeUTF(f.getName());
 836             if (!f.isPrimitive()) {
 837                 out.writeTypeString(f.getTypeString());
 838             }
 839         }
 840     }
 841 
 842     /**
 843      * Returns ClassNotFoundException (if any) thrown while attempting to
 844      * resolve local class corresponding to this class descriptor.
 845      */
 846     ClassNotFoundException getResolveException() {
 847         return resolveEx;
 848     }
 849 
 850     /**
 851      * Throws InternalError if not initialized.
 852      */
 853     private final void requireInitialized() {
 854         if (!initialized)
 855             throw new InternalError("Unexpected call when not initialized");
 856     }
 857 
 858     /**
 859      * Throws an InvalidClassException if object instances referencing this
 860      * class descriptor should not be allowed to deserialize.  This method does
 861      * not apply to deserialization of enum constants.
 862      */
 863     void checkDeserialize() throws InvalidClassException {
 864         requireInitialized();
 865         if (deserializeEx != null) {
 866             throw deserializeEx.newInvalidClassException();
 867         }
 868     }
 869 
 870     /**
 871      * Throws an InvalidClassException if objects whose class is represented by
 872      * this descriptor should not be allowed to serialize.  This method does
 873      * not apply to serialization of enum constants.
 874      */
 875     void checkSerialize() throws InvalidClassException {
 876         requireInitialized();
 877         if (serializeEx != null) {
 878             throw serializeEx.newInvalidClassException();
 879         }
 880     }
 881 
 882     /**
 883      * Throws an InvalidClassException if objects whose class is represented by
 884      * this descriptor should not be permitted to use default serialization
 885      * (e.g., if the class declares serializable fields that do not correspond
 886      * to actual fields, and hence must use the GetField API).  This method
 887      * does not apply to deserialization of enum constants.
 888      */
 889     void checkDefaultSerialize() throws InvalidClassException {
 890         requireInitialized();
 891         if (defaultSerializeEx != null) {
 892             throw defaultSerializeEx.newInvalidClassException();
 893         }
 894     }
 895 
 896     /**
 897      * Returns superclass descriptor.  Note that on the receiving side, the
 898      * superclass descriptor may be bound to a class that is not a superclass
 899      * of the subclass descriptor's bound class.
 900      */
 901     ObjectStreamClass getSuperDesc() {
 902         requireInitialized();
 903         return superDesc;
 904     }
 905 
 906     /**
 907      * Returns the "local" class descriptor for the class associated with this
 908      * class descriptor (i.e., the result of
 909      * ObjectStreamClass.lookup(this.forClass())) or null if there is no class
 910      * associated with this descriptor.
 911      */
 912     ObjectStreamClass getLocalDesc() {
 913         requireInitialized();
 914         return localDesc;
 915     }
 916 
 917     /**
 918      * Returns arrays of ObjectStreamFields representing the serializable
 919      * fields of the represented class.  If copy is true, a clone of this class
 920      * descriptor's field array is returned, otherwise the array itself is
 921      * returned.
 922      */
 923     ObjectStreamField[] getFields(boolean copy) {
 924         return copy ? fields.clone() : fields;
 925     }
 926 
 927     /**
 928      * Looks up a serializable field of the represented class by name and type.
 929      * A specified type of null matches all types, Object.class matches all
 930      * non-primitive types, and any other non-null type matches assignable
 931      * types only.  Returns matching field, or null if no match found.
 932      */
 933     ObjectStreamField getField(String name, Class<?> type) {
 934         for (int i = 0; i < fields.length; i++) {
 935             ObjectStreamField f = fields[i];
 936             if (f.getName().equals(name)) {
 937                 if (type == null ||
 938                     (type == Object.class && !f.isPrimitive()))
 939                 {
 940                     return f;
 941                 }
 942                 Class<?> ftype = f.getType();
 943                 if (ftype != null && type.isAssignableFrom(ftype)) {
 944                     return f;
 945                 }
 946             }
 947         }
 948         return null;
 949     }
 950 
 951     /**
 952      * Returns true if class descriptor represents a dynamic proxy class, false
 953      * otherwise.
 954      */
 955     boolean isProxy() {
 956         requireInitialized();
 957         return isProxy;
 958     }
 959 
 960     /**
 961      * Returns true if class descriptor represents an enum type, false
 962      * otherwise.
 963      */
 964     boolean isEnum() {
 965         requireInitialized();
 966         return isEnum;
 967     }
 968 
 969     /**
 970      * Returns true if represented class implements Externalizable, false
 971      * otherwise.
 972      */
 973     boolean isExternalizable() {
 974         requireInitialized();
 975         return externalizable;
 976     }
 977 
 978     /**
 979      * Returns true if represented class implements Serializable, false
 980      * otherwise.
 981      */
 982     boolean isSerializable() {
 983         requireInitialized();
 984         return serializable;
 985     }
 986 
 987     /**
 988      * Returns true if class descriptor represents externalizable class that
 989      * has written its data in 1.2 (block data) format, false otherwise.
 990      */
 991     boolean hasBlockExternalData() {
 992         requireInitialized();
 993         return hasBlockExternalData;
 994     }
 995 
 996     /**
 997      * Returns true if class descriptor represents serializable (but not
 998      * externalizable) class which has written its data via a custom
 999      * writeObject() method, false otherwise.
1000      */
1001     boolean hasWriteObjectData() {
1002         requireInitialized();
1003         return hasWriteObjectData;
1004     }
1005 
1006     /**
1007      * Returns true if represented class is serializable/externalizable and can
1008      * be instantiated by the serialization runtime--i.e., if it is
1009      * externalizable and defines a public no-arg constructor, or if it is
1010      * non-externalizable and its first non-serializable superclass defines an
1011      * accessible no-arg constructor.  Otherwise, returns false.
1012      */
1013     boolean isInstantiable() {
1014         requireInitialized();
1015         return (cons != null);
1016     }
1017 
1018     /**
1019      * Returns true if represented class is serializable (but not
1020      * externalizable) and defines a conformant writeObject method.  Otherwise,
1021      * returns false.
1022      */
1023     boolean hasWriteObjectMethod() {
1024         requireInitialized();
1025         return (writeObjectMethod != null);
1026     }
1027 
1028     /**
1029      * Returns true if represented class is serializable (but not
1030      * externalizable) and defines a conformant readObject method.  Otherwise,
1031      * returns false.
1032      */
1033     boolean hasReadObjectMethod() {
1034         requireInitialized();
1035         return (readObjectMethod != null);
1036     }
1037 
1038     /**
1039      * Returns true if represented class is serializable (but not
1040      * externalizable) and defines a conformant readObjectNoData method.
1041      * Otherwise, returns false.
1042      */
1043     boolean hasReadObjectNoDataMethod() {
1044         requireInitialized();
1045         return (readObjectNoDataMethod != null);
1046     }
1047 
1048     /**
1049      * Returns true if represented class is serializable or externalizable and
1050      * defines a conformant writeReplace method.  Otherwise, returns false.
1051      */
1052     boolean hasWriteReplaceMethod() {
1053         requireInitialized();
1054         return (writeReplaceMethod != null);
1055     }
1056 
1057     /**
1058      * Returns true if represented class is serializable or externalizable and
1059      * defines a conformant readResolve method.  Otherwise, returns false.
1060      */
1061     boolean hasReadResolveMethod() {
1062         requireInitialized();
1063         return (readResolveMethod != null);
1064     }
1065 
1066     /**
1067      * Creates a new instance of the represented class.  If the class is
1068      * externalizable, invokes its public no-arg constructor; otherwise, if the
1069      * class is serializable, invokes the no-arg constructor of the first
1070      * non-serializable superclass.  Throws UnsupportedOperationException if
1071      * this class descriptor is not associated with a class, if the associated
1072      * class is non-serializable or if the appropriate no-arg constructor is
1073      * inaccessible/unavailable.
1074      */
1075     Object newInstance()
1076         throws InstantiationException, InvocationTargetException,
1077                UnsupportedOperationException
1078     {
1079         requireInitialized();
1080         if (cons != null) {
1081             try {
1082                 if (domains == null || domains.length == 0) {
1083                     return cons.newInstance();
1084                 } else {
1085                     JavaSecurityAccess jsa = SharedSecrets.getJavaSecurityAccess();
1086                     PrivilegedAction<?> pea = () -> {
1087                         try {
1088                             return cons.newInstance();
1089                         } catch (InstantiationException
1090                                  | InvocationTargetException
1091                                  | IllegalAccessException x) {
1092                             throw new UndeclaredThrowableException(x);
1093                         }
1094                     }; // Can't use PrivilegedExceptionAction with jsa
1095                     try {
1096                         return jsa.doIntersectionPrivilege(pea,
1097                                    AccessController.getContext(),
1098                                    new AccessControlContext(domains));
1099                     } catch (UndeclaredThrowableException x) {
1100                         Throwable cause = x.getCause();
1101                         if (cause instanceof InstantiationException)
1102                             throw (InstantiationException) cause;
1103                         if (cause instanceof InvocationTargetException)
1104                             throw (InvocationTargetException) cause;
1105                         if (cause instanceof IllegalAccessException)
1106                             throw (IllegalAccessException) cause;
1107                         // not supposed to happen
1108                         throw x;
1109                     }
1110                 }
1111             } catch (IllegalAccessException ex) {
1112                 // should not occur, as access checks have been suppressed
1113                 throw new InternalError(ex);
1114             }
1115         } else {
1116             throw new UnsupportedOperationException();
1117         }
1118     }
1119 
1120     /**
1121      * Invokes the writeObject method of the represented serializable class.
1122      * Throws UnsupportedOperationException if this class descriptor is not
1123      * associated with a class, or if the class is externalizable,
1124      * non-serializable or does not define writeObject.
1125      */
1126     void invokeWriteObject(Object obj, ObjectOutputStream out)
1127         throws IOException, UnsupportedOperationException
1128     {
1129         requireInitialized();
1130         if (writeObjectMethod != null) {
1131             try {
1132                 writeObjectMethod.invoke(obj, new Object[]{ out });
1133             } catch (InvocationTargetException ex) {
1134                 Throwable th = ex.getTargetException();
1135                 if (th instanceof IOException) {
1136                     throw (IOException) th;
1137                 } else {
1138                     throwMiscException(th);
1139                 }
1140             } catch (IllegalAccessException ex) {
1141                 // should not occur, as access checks have been suppressed
1142                 throw new InternalError(ex);
1143             }
1144         } else {
1145             throw new UnsupportedOperationException();
1146         }
1147     }
1148 
1149     /**
1150      * Invokes the readObject method of the represented serializable class.
1151      * Throws UnsupportedOperationException if this class descriptor is not
1152      * associated with a class, or if the class is externalizable,
1153      * non-serializable or does not define readObject.
1154      */
1155     void invokeReadObject(Object obj, ObjectInputStream in)
1156         throws ClassNotFoundException, IOException,
1157                UnsupportedOperationException
1158     {
1159         requireInitialized();
1160         if (readObjectMethod != null) {
1161             try {
1162                 readObjectMethod.invoke(obj, new Object[]{ in });
1163             } catch (InvocationTargetException ex) {
1164                 Throwable th = ex.getTargetException();
1165                 if (th instanceof ClassNotFoundException) {
1166                     throw (ClassNotFoundException) th;
1167                 } else if (th instanceof IOException) {
1168                     throw (IOException) th;
1169                 } else {
1170                     throwMiscException(th);
1171                 }
1172             } catch (IllegalAccessException ex) {
1173                 // should not occur, as access checks have been suppressed
1174                 throw new InternalError(ex);
1175             }
1176         } else {
1177             throw new UnsupportedOperationException();
1178         }
1179     }
1180 
1181     /**
1182      * Invokes the readObjectNoData method of the represented serializable
1183      * class.  Throws UnsupportedOperationException if this class descriptor is
1184      * not associated with a class, or if the class is externalizable,
1185      * non-serializable or does not define readObjectNoData.
1186      */
1187     void invokeReadObjectNoData(Object obj)
1188         throws IOException, UnsupportedOperationException
1189     {
1190         requireInitialized();
1191         if (readObjectNoDataMethod != null) {
1192             try {
1193                 readObjectNoDataMethod.invoke(obj, (Object[]) null);
1194             } catch (InvocationTargetException ex) {
1195                 Throwable th = ex.getTargetException();
1196                 if (th instanceof ObjectStreamException) {
1197                     throw (ObjectStreamException) th;
1198                 } else {
1199                     throwMiscException(th);
1200                 }
1201             } catch (IllegalAccessException ex) {
1202                 // should not occur, as access checks have been suppressed
1203                 throw new InternalError(ex);
1204             }
1205         } else {
1206             throw new UnsupportedOperationException();
1207         }
1208     }
1209 
1210     /**
1211      * Invokes the writeReplace method of the represented serializable class and
1212      * returns the result.  Throws UnsupportedOperationException if this class
1213      * descriptor is not associated with a class, or if the class is
1214      * non-serializable or does not define writeReplace.
1215      */
1216     Object invokeWriteReplace(Object obj)
1217         throws IOException, UnsupportedOperationException
1218     {
1219         requireInitialized();
1220         if (writeReplaceMethod != null) {
1221             try {
1222                 return writeReplaceMethod.invoke(obj, (Object[]) null);
1223             } catch (InvocationTargetException ex) {
1224                 Throwable th = ex.getTargetException();
1225                 if (th instanceof ObjectStreamException) {
1226                     throw (ObjectStreamException) th;
1227                 } else {
1228                     throwMiscException(th);
1229                     throw new InternalError(th);  // never reached
1230                 }
1231             } catch (IllegalAccessException ex) {
1232                 // should not occur, as access checks have been suppressed
1233                 throw new InternalError(ex);
1234             }
1235         } else {
1236             throw new UnsupportedOperationException();
1237         }
1238     }
1239 
1240     /**
1241      * Invokes the readResolve method of the represented serializable class and
1242      * returns the result.  Throws UnsupportedOperationException if this class
1243      * descriptor is not associated with a class, or if the class is
1244      * non-serializable or does not define readResolve.
1245      */
1246     Object invokeReadResolve(Object obj)
1247         throws IOException, UnsupportedOperationException
1248     {
1249         requireInitialized();
1250         if (readResolveMethod != null) {
1251             try {
1252                 return readResolveMethod.invoke(obj, (Object[]) null);
1253             } catch (InvocationTargetException ex) {
1254                 Throwable th = ex.getTargetException();
1255                 if (th instanceof ObjectStreamException) {
1256                     throw (ObjectStreamException) th;
1257                 } else {
1258                     throwMiscException(th);
1259                     throw new InternalError(th);  // never reached
1260                 }
1261             } catch (IllegalAccessException ex) {
1262                 // should not occur, as access checks have been suppressed
1263                 throw new InternalError(ex);
1264             }
1265         } else {
1266             throw new UnsupportedOperationException();
1267         }
1268     }
1269 
1270     /**
1271      * Class representing the portion of an object's serialized form allotted
1272      * to data described by a given class descriptor.  If "hasData" is false,
1273      * the object's serialized form does not contain data associated with the
1274      * class descriptor.
1275      */
1276     static class ClassDataSlot {
1277 
1278         /** class descriptor "occupying" this slot */
1279         final ObjectStreamClass desc;
1280         /** true if serialized form includes data for this slot's descriptor */
1281         final boolean hasData;
1282 
1283         ClassDataSlot(ObjectStreamClass desc, boolean hasData) {
1284             this.desc = desc;
1285             this.hasData = hasData;
1286         }
1287     }
1288 
1289     /**
1290      * Returns array of ClassDataSlot instances representing the data layout
1291      * (including superclass data) for serialized objects described by this
1292      * class descriptor.  ClassDataSlots are ordered by inheritance with those
1293      * containing "higher" superclasses appearing first.  The final
1294      * ClassDataSlot contains a reference to this descriptor.
1295      */
1296     ClassDataSlot[] getClassDataLayout() throws InvalidClassException {
1297         // REMIND: synchronize instead of relying on volatile?
1298         if (dataLayout == null) {
1299             dataLayout = getClassDataLayout0();
1300         }
1301         return dataLayout;
1302     }
1303 
1304     private ClassDataSlot[] getClassDataLayout0()
1305         throws InvalidClassException
1306     {
1307         ArrayList<ClassDataSlot> slots = new ArrayList<>();
1308         Class<?> start = cl, end = cl;
1309 
1310         // locate closest non-serializable superclass
1311         while (end != null && Serializable.class.isAssignableFrom(end)) {
1312             end = end.getSuperclass();
1313         }
1314 
1315         HashSet<String> oscNames = new HashSet<>(3);
1316 
1317         for (ObjectStreamClass d = this; d != null; d = d.superDesc) {
1318             if (oscNames.contains(d.name)) {
1319                 throw new InvalidClassException("Circular reference.");
1320             } else {
1321                 oscNames.add(d.name);
1322             }
1323 
1324             // search up inheritance hierarchy for class with matching name
1325             String searchName = (d.cl != null) ? d.cl.getName() : d.name;
1326             Class<?> match = null;
1327             for (Class<?> c = start; c != end; c = c.getSuperclass()) {
1328                 if (searchName.equals(c.getName())) {
1329                     match = c;
1330                     break;
1331                 }
1332             }
1333 
1334             // add "no data" slot for each unmatched class below match
1335             if (match != null) {
1336                 for (Class<?> c = start; c != match; c = c.getSuperclass()) {
1337                     slots.add(new ClassDataSlot(
1338                         ObjectStreamClass.lookup(c, true), false));
1339                 }
1340                 start = match.getSuperclass();
1341             }
1342 
1343             // record descriptor/class pairing
1344             slots.add(new ClassDataSlot(d.getVariantFor(match), true));
1345         }
1346 
1347         // add "no data" slot for any leftover unmatched classes
1348         for (Class<?> c = start; c != end; c = c.getSuperclass()) {
1349             slots.add(new ClassDataSlot(
1350                 ObjectStreamClass.lookup(c, true), false));
1351         }
1352 
1353         // order slots from superclass -> subclass
1354         Collections.reverse(slots);
1355         return slots.toArray(new ClassDataSlot[slots.size()]);
1356     }
1357 
1358     /**
1359      * Returns aggregate size (in bytes) of marshalled primitive field values
1360      * for represented class.
1361      */
1362     int getPrimDataSize() {
1363         return primDataSize;
1364     }
1365 
1366     /**
1367      * Returns number of non-primitive serializable fields of represented
1368      * class.
1369      */
1370     int getNumObjFields() {
1371         return numObjFields;
1372     }
1373 
1374     /**
1375      * Fetches the serializable primitive field values of object obj and
1376      * marshals them into byte array buf starting at offset 0.  It is the
1377      * responsibility of the caller to ensure that obj is of the proper type if
1378      * non-null.
1379      */
1380     void getPrimFieldValues(Object obj, byte[] buf) {
1381         fieldRefl.getPrimFieldValues(obj, buf);
1382     }
1383 
1384     /**
1385      * Sets the serializable primitive fields of object obj using values
1386      * unmarshalled from byte array buf starting at offset 0.  It is the
1387      * responsibility of the caller to ensure that obj is of the proper type if
1388      * non-null.
1389      */
1390     void setPrimFieldValues(Object obj, byte[] buf) {
1391         fieldRefl.setPrimFieldValues(obj, buf);
1392     }
1393 
1394     /**
1395      * Fetches the serializable object field values of object obj and stores
1396      * them in array vals starting at offset 0.  It is the responsibility of
1397      * the caller to ensure that obj is of the proper type if non-null.
1398      */
1399     void getObjFieldValues(Object obj, Object[] vals) {
1400         fieldRefl.getObjFieldValues(obj, vals);
1401     }
1402 
1403     /**
1404      * Checks that the given values, from array vals starting at offset 0,
1405      * are assignable to the given serializable object fields.
1406      * @throws ClassCastException if any value is not assignable
1407      */
1408     void checkObjFieldValueTypes(Object obj, Object[] vals) {
1409         fieldRefl.checkObjectFieldValueTypes(obj, vals);
1410     }
1411 
1412     /**
1413      * Sets the serializable object fields of object obj using values from
1414      * array vals starting at offset 0.  It is the responsibility of the caller
1415      * to ensure that obj is of the proper type if non-null.
1416      */
1417     void setObjFieldValues(Object obj, Object[] vals) {
1418         fieldRefl.setObjFieldValues(obj, vals);
1419     }
1420 
1421     /**
1422      * Calculates and sets serializable field offsets, as well as primitive
1423      * data size and object field count totals.  Throws InvalidClassException
1424      * if fields are illegally ordered.
1425      */
1426     private void computeFieldOffsets() throws InvalidClassException {
1427         primDataSize = 0;
1428         numObjFields = 0;
1429         int firstObjIndex = -1;
1430 
1431         for (int i = 0; i < fields.length; i++) {
1432             ObjectStreamField f = fields[i];
1433             switch (f.getTypeCode()) {
1434                 case 'Z':
1435                 case 'B':
1436                     f.setOffset(primDataSize++);
1437                     break;
1438 
1439                 case 'C':
1440                 case 'S':
1441                     f.setOffset(primDataSize);
1442                     primDataSize += 2;
1443                     break;
1444 
1445                 case 'I':
1446                 case 'F':
1447                     f.setOffset(primDataSize);
1448                     primDataSize += 4;
1449                     break;
1450 
1451                 case 'J':
1452                 case 'D':
1453                     f.setOffset(primDataSize);
1454                     primDataSize += 8;
1455                     break;
1456 
1457                 case '[':
1458                 case 'L':
1459                     f.setOffset(numObjFields++);
1460                     if (firstObjIndex == -1) {
1461                         firstObjIndex = i;
1462                     }
1463                     break;
1464 
1465                 default:
1466                     throw new InternalError();
1467             }
1468         }
1469         if (firstObjIndex != -1 &&
1470             firstObjIndex + numObjFields != fields.length)
1471         {
1472             throw new InvalidClassException(name, "illegal field order");
1473         }
1474     }
1475 
1476     /**
1477      * If given class is the same as the class associated with this class
1478      * descriptor, returns reference to this class descriptor.  Otherwise,
1479      * returns variant of this class descriptor bound to given class.
1480      */
1481     private ObjectStreamClass getVariantFor(Class<?> cl)
1482         throws InvalidClassException
1483     {
1484         if (this.cl == cl) {
1485             return this;
1486         }
1487         ObjectStreamClass desc = new ObjectStreamClass();
1488         if (isProxy) {
1489             desc.initProxy(cl, null, superDesc);
1490         } else {
1491             desc.initNonProxy(this, cl, null, superDesc);
1492         }
1493         return desc;
1494     }
1495 
1496     /**
1497      * Returns public no-arg constructor of given class, or null if none found.
1498      * Access checks are disabled on the returned constructor (if any), since
1499      * the defining class may still be non-public.
1500      */
1501     private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
1502         try {
1503             Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
1504             cons.setAccessible(true);
1505             return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
1506                 cons : null;
1507         } catch (NoSuchMethodException ex) {
1508             return null;
1509         }
1510     }
1511 
1512     /**
1513      * Returns subclass-accessible no-arg constructor of first non-serializable
1514      * superclass, or null if none found.  Access checks are disabled on the
1515      * returned constructor (if any).
1516      */
1517     private static Constructor<?> getSerializableConstructor(Class<?> cl) {
1518         return reflFactory.newConstructorForSerialization(cl);
1519     }
1520 
1521     /**
1522      * Returns non-static, non-abstract method with given signature provided it
1523      * is defined by or accessible (via inheritance) by the given class, or
1524      * null if no match found.  Access checks are disabled on the returned
1525      * method (if any).
1526      */
1527     private static Method getInheritableMethod(Class<?> cl, String name,
1528                                                Class<?>[] argTypes,
1529                                                Class<?> returnType)
1530     {
1531         Method meth = null;
1532         Class<?> defCl = cl;
1533         while (defCl != null) {
1534             try {
1535                 meth = defCl.getDeclaredMethod(name, argTypes);
1536                 break;
1537             } catch (NoSuchMethodException ex) {
1538                 defCl = defCl.getSuperclass();
1539             }
1540         }
1541 
1542         if ((meth == null) || (meth.getReturnType() != returnType)) {
1543             return null;
1544         }
1545         meth.setAccessible(true);
1546         int mods = meth.getModifiers();
1547         if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
1548             return null;
1549         } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
1550             return meth;
1551         } else if ((mods & Modifier.PRIVATE) != 0) {
1552             return (cl == defCl) ? meth : null;
1553         } else {
1554             return packageEquals(cl, defCl) ? meth : null;
1555         }
1556     }
1557 
1558     /**
1559      * Returns non-static private method with given signature defined by given
1560      * class, or null if none found.  Access checks are disabled on the
1561      * returned method (if any).
1562      */
1563     private static Method getPrivateMethod(Class<?> cl, String name,
1564                                            Class<?>[] argTypes,
1565                                            Class<?> returnType)
1566     {
1567         try {
1568             Method meth = cl.getDeclaredMethod(name, argTypes);
1569             meth.setAccessible(true);
1570             int mods = meth.getModifiers();
1571             return ((meth.getReturnType() == returnType) &&
1572                     ((mods & Modifier.STATIC) == 0) &&
1573                     ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
1574         } catch (NoSuchMethodException ex) {
1575             return null;
1576         }
1577     }
1578 
1579     /**
1580      * Returns true if classes are defined in the same runtime package, false
1581      * otherwise.
1582      */
1583     private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
1584         return (cl1.getClassLoader() == cl2.getClassLoader() &&
1585                 cl1.getPackageName().equals(cl2.getPackageName()));
1586     }
1587 
1588     /**
1589      * Compares class names for equality, ignoring package names.  Returns true
1590      * if class names equal, false otherwise.
1591      */
1592     private static boolean classNamesEqual(String name1, String name2) {
1593         int idx1 = name1.lastIndexOf('.') + 1;
1594         int idx2 = name2.lastIndexOf('.') + 1;
1595         int len1 = name1.length() - idx1;
1596         int len2 = name2.length() - idx2;
1597         return len1 == len2 &&
1598                 name1.regionMatches(idx1, name2, idx2, len1);
1599     }
1600 
1601     /**
1602      * Returns JVM type signature for given list of parameters and return type.
1603      */
1604     private static String getMethodSignature(Class<?>[] paramTypes,
1605                                              Class<?> retType)
1606     {
1607         StringBuilder sb = new StringBuilder();
1608         sb.append('(');
1609         for (int i = 0; i < paramTypes.length; i++) {
1610             appendClassSignature(sb, paramTypes[i]);
1611         }
1612         sb.append(')');
1613         appendClassSignature(sb, retType);
1614         return sb.toString();
1615     }
1616 
1617     /**
1618      * Convenience method for throwing an exception that is either a
1619      * RuntimeException, Error, or of some unexpected type (in which case it is
1620      * wrapped inside an IOException).
1621      */
1622     private static void throwMiscException(Throwable th) throws IOException {
1623         if (th instanceof RuntimeException) {
1624             throw (RuntimeException) th;
1625         } else if (th instanceof Error) {
1626             throw (Error) th;
1627         } else {
1628             IOException ex = new IOException("unexpected exception type");
1629             ex.initCause(th);
1630             throw ex;
1631         }
1632     }
1633 
1634     /**
1635      * Returns ObjectStreamField array describing the serializable fields of
1636      * the given class.  Serializable fields backed by an actual field of the
1637      * class are represented by ObjectStreamFields with corresponding non-null
1638      * Field objects.  Throws InvalidClassException if the (explicitly
1639      * declared) serializable fields are invalid.
1640      */
1641     private static ObjectStreamField[] getSerialFields(Class<?> cl)
1642         throws InvalidClassException
1643     {
1644         ObjectStreamField[] fields;
1645         if (Serializable.class.isAssignableFrom(cl) &&
1646             !Externalizable.class.isAssignableFrom(cl) &&
1647             !Proxy.isProxyClass(cl) &&
1648             !cl.isInterface())
1649         {
1650             if ((fields = getDeclaredSerialFields(cl)) == null) {
1651                 fields = getDefaultSerialFields(cl);
1652             }
1653             Arrays.sort(fields);
1654         } else {
1655             fields = NO_FIELDS;
1656         }
1657         return fields;
1658     }
1659 
1660     /**
1661      * Returns serializable fields of given class as defined explicitly by a
1662      * "serialPersistentFields" field, or null if no appropriate
1663      * "serialPersistentFields" field is defined.  Serializable fields backed
1664      * by an actual field of the class are represented by ObjectStreamFields
1665      * with corresponding non-null Field objects.  For compatibility with past
1666      * releases, a "serialPersistentFields" field with a null value is
1667      * considered equivalent to not declaring "serialPersistentFields".  Throws
1668      * InvalidClassException if the declared serializable fields are
1669      * invalid--e.g., if multiple fields share the same name.
1670      */
1671     private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl)
1672         throws InvalidClassException
1673     {
1674         ObjectStreamField[] serialPersistentFields = null;
1675         try {
1676             Field f = cl.getDeclaredField("serialPersistentFields");
1677             int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
1678             if ((f.getModifiers() & mask) == mask) {
1679                 f.setAccessible(true);
1680                 serialPersistentFields = (ObjectStreamField[]) f.get(null);
1681             }
1682         } catch (Exception ex) {
1683         }
1684         if (serialPersistentFields == null) {
1685             return null;
1686         } else if (serialPersistentFields.length == 0) {
1687             return NO_FIELDS;
1688         }
1689 
1690         ObjectStreamField[] boundFields =
1691             new ObjectStreamField[serialPersistentFields.length];
1692         Set<String> fieldNames = new HashSet<>(serialPersistentFields.length);
1693 
1694         for (int i = 0; i < serialPersistentFields.length; i++) {
1695             ObjectStreamField spf = serialPersistentFields[i];
1696 
1697             String fname = spf.getName();
1698             if (fieldNames.contains(fname)) {
1699                 throw new InvalidClassException(
1700                     "multiple serializable fields named " + fname);
1701             }
1702             fieldNames.add(fname);
1703 
1704             try {
1705                 Field f = cl.getDeclaredField(fname);
1706                 if ((f.getType() == spf.getType()) &&
1707                     ((f.getModifiers() & Modifier.STATIC) == 0))
1708                 {
1709                     boundFields[i] =
1710                         new ObjectStreamField(f, spf.isUnshared(), true);
1711                 }
1712             } catch (NoSuchFieldException ex) {
1713             }
1714             if (boundFields[i] == null) {
1715                 boundFields[i] = new ObjectStreamField(
1716                     fname, spf.getType(), spf.isUnshared());
1717             }
1718         }
1719         return boundFields;
1720     }
1721 
1722     /**
1723      * Returns array of ObjectStreamFields corresponding to all non-static
1724      * non-transient fields declared by given class.  Each ObjectStreamField
1725      * contains a Field object for the field it represents.  If no default
1726      * serializable fields exist, NO_FIELDS is returned.
1727      */
1728     private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
1729         Field[] clFields = cl.getDeclaredFields();
1730         ArrayList<ObjectStreamField> list = new ArrayList<>();
1731         int mask = Modifier.STATIC | Modifier.TRANSIENT;
1732 
1733         for (int i = 0; i < clFields.length; i++) {
1734             if ((clFields[i].getModifiers() & mask) == 0) {
1735                 list.add(new ObjectStreamField(clFields[i], false, true));
1736             }
1737         }
1738         int size = list.size();
1739         return (size == 0) ? NO_FIELDS :
1740             list.toArray(new ObjectStreamField[size]);
1741     }
1742 
1743     /**
1744      * Returns explicit serial version UID value declared by given class, or
1745      * null if none.
1746      */
1747     private static Long getDeclaredSUID(Class<?> cl) {
1748         try {
1749             Field f = cl.getDeclaredField("serialVersionUID");
1750             int mask = Modifier.STATIC | Modifier.FINAL;
1751             if ((f.getModifiers() & mask) == mask) {
1752                 f.setAccessible(true);
1753                 return Long.valueOf(f.getLong(null));
1754             }
1755         } catch (Exception ex) {
1756         }
1757         return null;
1758     }
1759 
1760     /**
1761      * Computes the default serial version UID value for the given class.
1762      */
1763     private static long computeDefaultSUID(Class<?> cl) {
1764         if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
1765         {
1766             return 0L;
1767         }
1768 
1769         try {
1770             ByteArrayOutputStream bout = new ByteArrayOutputStream();
1771             DataOutputStream dout = new DataOutputStream(bout);
1772 
1773             dout.writeUTF(cl.getName());
1774 
1775             int classMods = cl.getModifiers() &
1776                 (Modifier.PUBLIC | Modifier.FINAL |
1777                  Modifier.INTERFACE | Modifier.ABSTRACT);
1778 
1779             /*
1780              * compensate for javac bug in which ABSTRACT bit was set for an
1781              * interface only if the interface declared methods
1782              */
1783             Method[] methods = cl.getDeclaredMethods();
1784             if ((classMods & Modifier.INTERFACE) != 0) {
1785                 classMods = (methods.length > 0) ?
1786                     (classMods | Modifier.ABSTRACT) :
1787                     (classMods & ~Modifier.ABSTRACT);
1788             }
1789             dout.writeInt(classMods);
1790 
1791             if (!cl.isArray()) {
1792                 /*
1793                  * compensate for change in 1.2FCS in which
1794                  * Class.getInterfaces() was modified to return Cloneable and
1795                  * Serializable for array classes.
1796                  */
1797                 Class<?>[] interfaces = cl.getInterfaces();
1798                 String[] ifaceNames = new String[interfaces.length];
1799                 for (int i = 0; i < interfaces.length; i++) {
1800                     ifaceNames[i] = interfaces[i].getName();
1801                 }
1802                 Arrays.sort(ifaceNames);
1803                 for (int i = 0; i < ifaceNames.length; i++) {
1804                     dout.writeUTF(ifaceNames[i]);
1805                 }
1806             }
1807 
1808             Field[] fields = cl.getDeclaredFields();
1809             MemberSignature[] fieldSigs = new MemberSignature[fields.length];
1810             for (int i = 0; i < fields.length; i++) {
1811                 fieldSigs[i] = new MemberSignature(fields[i]);
1812             }
1813             Arrays.sort(fieldSigs, new Comparator<>() {
1814                 public int compare(MemberSignature ms1, MemberSignature ms2) {
1815                     return ms1.name.compareTo(ms2.name);
1816                 }
1817             });
1818             for (int i = 0; i < fieldSigs.length; i++) {
1819                 MemberSignature sig = fieldSigs[i];
1820                 int mods = sig.member.getModifiers() &
1821                     (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
1822                      Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
1823                      Modifier.TRANSIENT);
1824                 if (((mods & Modifier.PRIVATE) == 0) ||
1825                     ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
1826                 {
1827                     dout.writeUTF(sig.name);
1828                     dout.writeInt(mods);
1829                     dout.writeUTF(sig.signature);
1830                 }
1831             }
1832 
1833             if (hasStaticInitializer(cl)) {
1834                 dout.writeUTF("<clinit>");
1835                 dout.writeInt(Modifier.STATIC);
1836                 dout.writeUTF("()V");
1837             }
1838 
1839             Constructor<?>[] cons = cl.getDeclaredConstructors();
1840             MemberSignature[] consSigs = new MemberSignature[cons.length];
1841             for (int i = 0; i < cons.length; i++) {
1842                 consSigs[i] = new MemberSignature(cons[i]);
1843             }
1844             Arrays.sort(consSigs, new Comparator<>() {
1845                 public int compare(MemberSignature ms1, MemberSignature ms2) {
1846                     return ms1.signature.compareTo(ms2.signature);
1847                 }
1848             });
1849             for (int i = 0; i < consSigs.length; i++) {
1850                 MemberSignature sig = consSigs[i];
1851                 int mods = sig.member.getModifiers() &
1852                     (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
1853                      Modifier.STATIC | Modifier.FINAL |
1854                      Modifier.SYNCHRONIZED | Modifier.NATIVE |
1855                      Modifier.ABSTRACT | Modifier.STRICT);
1856                 if ((mods & Modifier.PRIVATE) == 0) {
1857                     dout.writeUTF("<init>");
1858                     dout.writeInt(mods);
1859                     dout.writeUTF(sig.signature.replace('/', '.'));
1860                 }
1861             }
1862 
1863             MemberSignature[] methSigs = new MemberSignature[methods.length];
1864             for (int i = 0; i < methods.length; i++) {
1865                 methSigs[i] = new MemberSignature(methods[i]);
1866             }
1867             Arrays.sort(methSigs, new Comparator<>() {
1868                 public int compare(MemberSignature ms1, MemberSignature ms2) {
1869                     int comp = ms1.name.compareTo(ms2.name);
1870                     if (comp == 0) {
1871                         comp = ms1.signature.compareTo(ms2.signature);
1872                     }
1873                     return comp;
1874                 }
1875             });
1876             for (int i = 0; i < methSigs.length; i++) {
1877                 MemberSignature sig = methSigs[i];
1878                 int mods = sig.member.getModifiers() &
1879                     (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
1880                      Modifier.STATIC | Modifier.FINAL |
1881                      Modifier.SYNCHRONIZED | Modifier.NATIVE |
1882                      Modifier.ABSTRACT | Modifier.STRICT);
1883                 if ((mods & Modifier.PRIVATE) == 0) {
1884                     dout.writeUTF(sig.name);
1885                     dout.writeInt(mods);
1886                     dout.writeUTF(sig.signature.replace('/', '.'));
1887                 }
1888             }
1889 
1890             dout.flush();
1891 
1892             MessageDigest md = MessageDigest.getInstance("SHA");
1893             byte[] hashBytes = md.digest(bout.toByteArray());
1894             long hash = 0;
1895             for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
1896                 hash = (hash << 8) | (hashBytes[i] & 0xFF);
1897             }
1898             return hash;
1899         } catch (IOException ex) {
1900             throw new InternalError(ex);
1901         } catch (NoSuchAlgorithmException ex) {
1902             throw new SecurityException(ex.getMessage());
1903         }
1904     }
1905 
1906     /**
1907      * Returns true if the given class defines a static initializer method,
1908      * false otherwise.
1909      */
1910     private static native boolean hasStaticInitializer(Class<?> cl);
1911 
1912     /**
1913      * Class for computing and caching field/constructor/method signatures
1914      * during serialVersionUID calculation.
1915      */
1916     private static class MemberSignature {
1917 
1918         public final Member member;
1919         public final String name;
1920         public final String signature;
1921 
1922         public MemberSignature(Field field) {
1923             member = field;
1924             name = field.getName();
1925             signature = getClassSignature(field.getType());
1926         }
1927 
1928         public MemberSignature(Constructor<?> cons) {
1929             member = cons;
1930             name = cons.getName();
1931             signature = getMethodSignature(
1932                 cons.getParameterTypes(), Void.TYPE);
1933         }
1934 
1935         public MemberSignature(Method meth) {
1936             member = meth;
1937             name = meth.getName();
1938             signature = getMethodSignature(
1939                 meth.getParameterTypes(), meth.getReturnType());
1940         }
1941     }
1942 
1943     /**
1944      * Class for setting and retrieving serializable field values in batch.
1945      */
1946     // REMIND: dynamically generate these?
1947     private static class FieldReflector {
1948 
1949         /** handle for performing unsafe operations */
1950         private static final Unsafe unsafe = Unsafe.getUnsafe();
1951 
1952         /** fields to operate on */
1953         private final ObjectStreamField[] fields;
1954         /** number of primitive fields */
1955         private final int numPrimFields;
1956         /** unsafe field keys for reading fields - may contain dupes */
1957         private final long[] readKeys;
1958         /** unsafe fields keys for writing fields - no dupes */
1959         private final long[] writeKeys;
1960         /** field data offsets */
1961         private final int[] offsets;
1962         /** field type codes */
1963         private final char[] typeCodes;
1964         /** field types */
1965         private final Class<?>[] types;
1966 
1967         /**
1968          * Constructs FieldReflector capable of setting/getting values from the
1969          * subset of fields whose ObjectStreamFields contain non-null
1970          * reflective Field objects.  ObjectStreamFields with null Fields are
1971          * treated as filler, for which get operations return default values
1972          * and set operations discard given values.
1973          */
1974         FieldReflector(ObjectStreamField[] fields) {
1975             this.fields = fields;
1976             int nfields = fields.length;
1977             readKeys = new long[nfields];
1978             writeKeys = new long[nfields];
1979             offsets = new int[nfields];
1980             typeCodes = new char[nfields];
1981             ArrayList<Class<?>> typeList = new ArrayList<>();
1982             Set<Long> usedKeys = new HashSet<>();
1983 
1984 
1985             for (int i = 0; i < nfields; i++) {
1986                 ObjectStreamField f = fields[i];
1987                 Field rf = f.getField();
1988                 long key = (rf != null) ?
1989                     unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET;
1990                 readKeys[i] = key;
1991                 writeKeys[i] = usedKeys.add(key) ?
1992                     key : Unsafe.INVALID_FIELD_OFFSET;
1993                 offsets[i] = f.getOffset();
1994                 typeCodes[i] = f.getTypeCode();
1995                 if (!f.isPrimitive()) {
1996                     typeList.add((rf != null) ? rf.getType() : null);
1997                 }
1998             }
1999 
2000             types = typeList.toArray(new Class<?>[typeList.size()]);
2001             numPrimFields = nfields - types.length;
2002         }
2003 
2004         /**
2005          * Returns list of ObjectStreamFields representing fields operated on
2006          * by this reflector.  The shared/unshared values and Field objects
2007          * contained by ObjectStreamFields in the list reflect their bindings
2008          * to locally defined serializable fields.
2009          */
2010         ObjectStreamField[] getFields() {
2011             return fields;
2012         }
2013 
2014         /**
2015          * Fetches the serializable primitive field values of object obj and
2016          * marshals them into byte array buf starting at offset 0.  The caller
2017          * is responsible for ensuring that obj is of the proper type.
2018          */
2019         void getPrimFieldValues(Object obj, byte[] buf) {
2020             if (obj == null) {
2021                 throw new NullPointerException();
2022             }
2023             /* assuming checkDefaultSerialize() has been called on the class
2024              * descriptor this FieldReflector was obtained from, no field keys
2025              * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
2026              */
2027             for (int i = 0; i < numPrimFields; i++) {
2028                 long key = readKeys[i];
2029                 int off = offsets[i];
2030                 switch (typeCodes[i]) {
2031                     case 'Z':
2032                         Bits.putBoolean(buf, off, unsafe.getBoolean(obj, key));
2033                         break;
2034 
2035                     case 'B':
2036                         buf[off] = unsafe.getByte(obj, key);
2037                         break;
2038 
2039                     case 'C':
2040                         Bits.putChar(buf, off, unsafe.getChar(obj, key));
2041                         break;
2042 
2043                     case 'S':
2044                         Bits.putShort(buf, off, unsafe.getShort(obj, key));
2045                         break;
2046 
2047                     case 'I':
2048                         Bits.putInt(buf, off, unsafe.getInt(obj, key));
2049                         break;
2050 
2051                     case 'F':
2052                         Bits.putFloat(buf, off, unsafe.getFloat(obj, key));
2053                         break;
2054 
2055                     case 'J':
2056                         Bits.putLong(buf, off, unsafe.getLong(obj, key));
2057                         break;
2058 
2059                     case 'D':
2060                         Bits.putDouble(buf, off, unsafe.getDouble(obj, key));
2061                         break;
2062 
2063                     default:
2064                         throw new InternalError();
2065                 }
2066             }
2067         }
2068 
2069         /**
2070          * Sets the serializable primitive fields of object obj using values
2071          * unmarshalled from byte array buf starting at offset 0.  The caller
2072          * is responsible for ensuring that obj is of the proper type.
2073          */
2074         void setPrimFieldValues(Object obj, byte[] buf) {
2075             if (obj == null) {
2076                 throw new NullPointerException();
2077             }
2078             for (int i = 0; i < numPrimFields; i++) {
2079                 long key = writeKeys[i];
2080                 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2081                     continue;           // discard value
2082                 }
2083                 int off = offsets[i];
2084                 switch (typeCodes[i]) {
2085                     case 'Z':
2086                         unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off));
2087                         break;
2088 
2089                     case 'B':
2090                         unsafe.putByte(obj, key, buf[off]);
2091                         break;
2092 
2093                     case 'C':
2094                         unsafe.putChar(obj, key, Bits.getChar(buf, off));
2095                         break;
2096 
2097                     case 'S':
2098                         unsafe.putShort(obj, key, Bits.getShort(buf, off));
2099                         break;
2100 
2101                     case 'I':
2102                         unsafe.putInt(obj, key, Bits.getInt(buf, off));
2103                         break;
2104 
2105                     case 'F':
2106                         unsafe.putFloat(obj, key, Bits.getFloat(buf, off));
2107                         break;
2108 
2109                     case 'J':
2110                         unsafe.putLong(obj, key, Bits.getLong(buf, off));
2111                         break;
2112 
2113                     case 'D':
2114                         unsafe.putDouble(obj, key, Bits.getDouble(buf, off));
2115                         break;
2116 
2117                     default:
2118                         throw new InternalError();
2119                 }
2120             }
2121         }
2122 
2123         /**
2124          * Fetches the serializable object field values of object obj and
2125          * stores them in array vals starting at offset 0.  The caller is
2126          * responsible for ensuring that obj is of the proper type.
2127          */
2128         void getObjFieldValues(Object obj, Object[] vals) {
2129             if (obj == null) {
2130                 throw new NullPointerException();
2131             }
2132             /* assuming checkDefaultSerialize() has been called on the class
2133              * descriptor this FieldReflector was obtained from, no field keys
2134              * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
2135              */
2136             for (int i = numPrimFields; i < fields.length; i++) {
2137                 switch (typeCodes[i]) {
2138                     case 'L':
2139                     case '[':
2140                         vals[offsets[i]] = unsafe.getReference(obj, readKeys[i]);
2141                         break;
2142 
2143                     default:
2144                         throw new InternalError();
2145                 }
2146             }
2147         }
2148 
2149         /**
2150          * Checks that the given values, from array vals starting at offset 0,
2151          * are assignable to the given serializable object fields.
2152          * @throws ClassCastException if any value is not assignable
2153          */
2154         void checkObjectFieldValueTypes(Object obj, Object[] vals) {
2155             setObjFieldValues(obj, vals, true);
2156         }
2157 
2158         /**
2159          * Sets the serializable object fields of object obj using values from
2160          * array vals starting at offset 0.  The caller is responsible for
2161          * ensuring that obj is of the proper type; however, attempts to set a
2162          * field with a value of the wrong type will trigger an appropriate
2163          * ClassCastException.
2164          */
2165         void setObjFieldValues(Object obj, Object[] vals) {
2166             setObjFieldValues(obj, vals, false);
2167         }
2168 
2169         private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) {
2170             if (obj == null) {
2171                 throw new NullPointerException();
2172             }
2173             for (int i = numPrimFields; i < fields.length; i++) {
2174                 long key = writeKeys[i];
2175                 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2176                     continue;           // discard value
2177                 }
2178                 switch (typeCodes[i]) {
2179                     case 'L':
2180                     case '[':
2181                         Object val = vals[offsets[i]];
2182                         if (val != null &&
2183                             !types[i - numPrimFields].isInstance(val))
2184                         {
2185                             Field f = fields[i].getField();
2186                             throw new ClassCastException(
2187                                 "cannot assign instance of " +
2188                                 val.getClass().getName() + " to field " +
2189                                 f.getDeclaringClass().getName() + "." +
2190                                 f.getName() + " of type " +
2191                                 f.getType().getName() + " in instance of " +
2192                                 obj.getClass().getName());
2193                         }
2194                         if (!dryRun)
2195                             unsafe.putReference(obj, key, val);
2196                         break;
2197 
2198                     default:
2199                         throw new InternalError();
2200                 }
2201             }
2202         }
2203     }
2204 
2205     /**
2206      * Matches given set of serializable fields with serializable fields
2207      * described by the given local class descriptor, and returns a
2208      * FieldReflector instance capable of setting/getting values from the
2209      * subset of fields that match (non-matching fields are treated as filler,
2210      * for which get operations return default values and set operations
2211      * discard given values).  Throws InvalidClassException if unresolvable
2212      * type conflicts exist between the two sets of fields.
2213      */
2214     private static FieldReflector getReflector(ObjectStreamField[] fields,
2215                                                ObjectStreamClass localDesc)
2216         throws InvalidClassException
2217     {
2218         // class irrelevant if no fields
2219         Class<?> cl = (localDesc != null && fields.length > 0) ?
2220             localDesc.cl : null;
2221         processQueue(Caches.reflectorsQueue, Caches.reflectors);
2222         FieldReflectorKey key = new FieldReflectorKey(cl, fields,
2223                                                       Caches.reflectorsQueue);
2224         Reference<?> ref = Caches.reflectors.get(key);
2225         Object entry = null;
2226         if (ref != null) {
2227             entry = ref.get();
2228         }
2229         EntryFuture future = null;
2230         if (entry == null) {
2231             EntryFuture newEntry = new EntryFuture();
2232             Reference<?> newRef = new SoftReference<>(newEntry);
2233             do {
2234                 if (ref != null) {
2235                     Caches.reflectors.remove(key, ref);
2236                 }
2237                 ref = Caches.reflectors.putIfAbsent(key, newRef);
2238                 if (ref != null) {
2239                     entry = ref.get();
2240                 }
2241             } while (ref != null && entry == null);
2242             if (entry == null) {
2243                 future = newEntry;
2244             }
2245         }
2246 
2247         if (entry instanceof FieldReflector) {  // check common case first
2248             return (FieldReflector) entry;
2249         } else if (entry instanceof EntryFuture) {
2250             entry = ((EntryFuture) entry).get();
2251         } else if (entry == null) {
2252             try {
2253                 entry = new FieldReflector(matchFields(fields, localDesc));
2254             } catch (Throwable th) {
2255                 entry = th;
2256             }
2257             future.set(entry);
2258             Caches.reflectors.put(key, new SoftReference<>(entry));
2259         }
2260 
2261         if (entry instanceof FieldReflector) {
2262             return (FieldReflector) entry;
2263         } else if (entry instanceof InvalidClassException) {
2264             throw (InvalidClassException) entry;
2265         } else if (entry instanceof RuntimeException) {
2266             throw (RuntimeException) entry;
2267         } else if (entry instanceof Error) {
2268             throw (Error) entry;
2269         } else {
2270             throw new InternalError("unexpected entry: " + entry);
2271         }
2272     }
2273 
2274     /**
2275      * FieldReflector cache lookup key.  Keys are considered equal if they
2276      * refer to the same class and equivalent field formats.
2277      */
2278     private static class FieldReflectorKey extends WeakReference<Class<?>> {
2279 
2280         private final String[] sigs;
2281         private final int hash;
2282         private final boolean nullClass;
2283 
2284         FieldReflectorKey(Class<?> cl, ObjectStreamField[] fields,
2285                           ReferenceQueue<Class<?>> queue)
2286         {
2287             super(cl, queue);
2288             nullClass = (cl == null);
2289             sigs = new String[2 * fields.length];
2290             for (int i = 0, j = 0; i < fields.length; i++) {
2291                 ObjectStreamField f = fields[i];
2292                 sigs[j++] = f.getName();
2293                 sigs[j++] = f.getSignature();
2294             }
2295             hash = System.identityHashCode(cl) + Arrays.hashCode(sigs);
2296         }
2297 
2298         public int hashCode() {
2299             return hash;
2300         }
2301 
2302         public boolean equals(Object obj) {
2303             if (obj == this) {
2304                 return true;
2305             }
2306 
2307             if (obj instanceof FieldReflectorKey) {
2308                 FieldReflectorKey other = (FieldReflectorKey) obj;
2309                 Class<?> referent;
2310                 return (nullClass ? other.nullClass
2311                                   : ((referent = get()) != null) &&
2312                                     (referent == other.get())) &&
2313                         Arrays.equals(sigs, other.sigs);
2314             } else {
2315                 return false;
2316             }
2317         }
2318     }
2319 
2320     /**
2321      * Matches given set of serializable fields with serializable fields
2322      * obtained from the given local class descriptor (which contain bindings
2323      * to reflective Field objects).  Returns list of ObjectStreamFields in
2324      * which each ObjectStreamField whose signature matches that of a local
2325      * field contains a Field object for that field; unmatched
2326      * ObjectStreamFields contain null Field objects.  Shared/unshared settings
2327      * of the returned ObjectStreamFields also reflect those of matched local
2328      * ObjectStreamFields.  Throws InvalidClassException if unresolvable type
2329      * conflicts exist between the two sets of fields.
2330      */
2331     private static ObjectStreamField[] matchFields(ObjectStreamField[] fields,
2332                                                    ObjectStreamClass localDesc)
2333         throws InvalidClassException
2334     {
2335         ObjectStreamField[] localFields = (localDesc != null) ?
2336             localDesc.fields : NO_FIELDS;
2337 
2338         /*
2339          * Even if fields == localFields, we cannot simply return localFields
2340          * here.  In previous implementations of serialization,
2341          * ObjectStreamField.getType() returned Object.class if the
2342          * ObjectStreamField represented a non-primitive field and belonged to
2343          * a non-local class descriptor.  To preserve this (questionable)
2344          * behavior, the ObjectStreamField instances returned by matchFields
2345          * cannot report non-primitive types other than Object.class; hence
2346          * localFields cannot be returned directly.
2347          */
2348 
2349         ObjectStreamField[] matches = new ObjectStreamField[fields.length];
2350         for (int i = 0; i < fields.length; i++) {
2351             ObjectStreamField f = fields[i], m = null;
2352             for (int j = 0; j < localFields.length; j++) {
2353                 ObjectStreamField lf = localFields[j];
2354                 if (f.getName().equals(lf.getName())) {
2355                     if ((f.isPrimitive() || lf.isPrimitive()) &&
2356                         f.getTypeCode() != lf.getTypeCode())
2357                     {
2358                         throw new InvalidClassException(localDesc.name,
2359                             "incompatible types for field " + f.getName());
2360                     }
2361                     if (lf.getField() != null) {
2362                         m = new ObjectStreamField(
2363                             lf.getField(), lf.isUnshared(), false);
2364                     } else {
2365                         m = new ObjectStreamField(
2366                             lf.getName(), lf.getSignature(), lf.isUnshared());
2367                     }
2368                 }
2369             }
2370             if (m == null) {
2371                 m = new ObjectStreamField(
2372                     f.getName(), f.getSignature(), false);
2373             }
2374             m.setOffset(f.getOffset());
2375             matches[i] = m;
2376         }
2377         return matches;
2378     }
2379 
2380     /**
2381      * Removes from the specified map any keys that have been enqueued
2382      * on the specified reference queue.
2383      */
2384     static void processQueue(ReferenceQueue<Class<?>> queue,
2385                              ConcurrentMap<? extends
2386                              WeakReference<Class<?>>, ?> map)
2387     {
2388         Reference<? extends Class<?>> ref;
2389         while((ref = queue.poll()) != null) {
2390             map.remove(ref);
2391         }
2392     }
2393 
2394     /**
2395      *  Weak key for Class objects.
2396      *
2397      **/
2398     static class WeakClassKey extends WeakReference<Class<?>> {
2399         /**
2400          * saved value of the referent's identity hash code, to maintain
2401          * a consistent hash code after the referent has been cleared
2402          */
2403         private final int hash;
2404 
2405         /**
2406          * Create a new WeakClassKey to the given object, registered
2407          * with a queue.
2408          */
2409         WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
2410             super(cl, refQueue);
2411             hash = System.identityHashCode(cl);
2412         }
2413 
2414         /**
2415          * Returns the identity hash code of the original referent.
2416          */
2417         public int hashCode() {
2418             return hash;
2419         }
2420 
2421         /**
2422          * Returns true if the given object is this identical
2423          * WeakClassKey instance, or, if this object's referent has not
2424          * been cleared, if the given object is another WeakClassKey
2425          * instance with the identical non-null referent as this one.
2426          */
2427         public boolean equals(Object obj) {
2428             if (obj == this) {
2429                 return true;
2430             }
2431 
2432             if (obj instanceof WeakClassKey) {
2433                 Object referent = get();
2434                 return (referent != null) &&
2435                        (referent == ((WeakClassKey) obj).get());
2436             } else {
2437                 return false;
2438             }
2439         }
2440     }
2441 }