1 /*
   2  * Copyright (c) 2003, 2012, 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 com.sun.java.util.jar.pack;
  27 
  28 import com.sun.java.util.jar.pack.ConstantPool.Entry;
  29 import com.sun.java.util.jar.pack.ConstantPool.Index;
  30 import java.io.ByteArrayOutputStream;
  31 import java.io.IOException;
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.Collection;
  35 import java.util.Collections;
  36 import java.util.HashMap;
  37 import java.util.List;
  38 import java.util.Map;
  39 import static com.sun.java.util.jar.pack.Constants.*;
  40 
  41 /**
  42  * Represents an attribute in a class-file.
  43  * Takes care to remember where constant pool indexes occur.
  44  * Implements the "little language" of Pack200 for describing
  45  * attribute layouts.
  46  * @author John Rose
  47  */
  48 class Attribute implements Comparable<Attribute> {
  49     // Attribute instance fields.
  50 
  51     Layout def;     // the name and format of this attr
  52     byte[] bytes;   // the actual bytes
  53     Object fixups;  // reference relocations, if any are required
  54 
  55     public String name() { return def.name(); }
  56     public Layout layout() { return def; }
  57     public byte[] bytes() { return bytes; }
  58     public int size() { return bytes.length; }
  59     public Entry getNameRef() { return def.getNameRef(); }
  60 
  61     private Attribute(Attribute old) {
  62         this.def = old.def;
  63         this.bytes = old.bytes;
  64         this.fixups = old.fixups;
  65     }
  66 
  67     public Attribute(Layout def, byte[] bytes, Object fixups) {
  68         this.def = def;
  69         this.bytes = bytes;
  70         this.fixups = fixups;
  71         Fixups.setBytes(fixups, bytes);
  72     }
  73     public Attribute(Layout def, byte[] bytes) {
  74         this(def, bytes, null);
  75     }
  76 
  77     public Attribute addContent(byte[] bytes, Object fixups) {
  78         assert(isCanonical());
  79         if (bytes.length == 0 && fixups == null)
  80             return this;
  81         Attribute res = new Attribute(this);
  82         res.bytes = bytes;
  83         res.fixups = fixups;
  84         Fixups.setBytes(fixups, bytes);
  85         return res;
  86     }
  87     public Attribute addContent(byte[] bytes) {
  88         return addContent(bytes, null);
  89     }
  90 
  91     public void finishRefs(Index ix) {
  92         if (fixups != null) {
  93             Fixups.finishRefs(fixups, bytes, ix);
  94             fixups = null;
  95         }
  96     }
  97 
  98     public boolean isCanonical() {
  99         return this == def.canon;
 100     }
 101 
 102     public int compareTo(Attribute that) {
 103         return this.def.compareTo(that.def);
 104     }
 105 
 106     private static final Map<List<Attribute>, List<Attribute>> canonLists = new HashMap<>();
 107     private static final Map<Layout, Attribute> attributes = new HashMap<>();
 108     private static final Map<Layout, Attribute> standardDefs = new HashMap<>();
 109 
 110     // Canonicalized lists of trivial attrs (Deprecated, etc.)
 111     // are used by trimToSize, in order to reduce footprint
 112     // of some common cases.  (Note that Code attributes are
 113     // always zero size.)
 114     public static List<Attribute> getCanonList(List<Attribute> al) {
 115         synchronized (canonLists) {
 116             List<Attribute> cl = canonLists.get(al);
 117             if (cl == null) {
 118                 cl = new ArrayList<>(al.size());
 119                 cl.addAll(al);
 120                 cl = Collections.unmodifiableList(cl);
 121                 canonLists.put(al, cl);
 122             }
 123             return cl;
 124         }
 125     }
 126 
 127     // Find the canonical empty attribute with the given ctype, name, layout.
 128     public static Attribute find(int ctype, String name, String layout) {
 129         Layout key = Layout.makeKey(ctype, name, layout);
 130         synchronized (attributes) {
 131             Attribute a = attributes.get(key);
 132             if (a == null) {
 133                 a = new Layout(ctype, name, layout).canonicalInstance();
 134                 attributes.put(key, a);
 135             }
 136             return a;
 137         }
 138     }
 139 
 140     public static Layout keyForLookup(int ctype, String name) {
 141         return Layout.makeKey(ctype, name);
 142     }
 143 
 144     // Find canonical empty attribute with given ctype and name,
 145     // and with the standard layout.
 146     public static Attribute lookup(Map<Layout, Attribute> defs, int ctype,
 147             String name) {
 148         if (defs == null) {
 149             defs = standardDefs;
 150         }
 151         return defs.get(Layout.makeKey(ctype, name));
 152     }
 153 
 154     public static Attribute define(Map<Layout, Attribute> defs, int ctype,
 155             String name, String layout) {
 156         Attribute a = find(ctype, name, layout);
 157         defs.put(Layout.makeKey(ctype, name), a);
 158         return a;
 159     }
 160 
 161     static {
 162         Map<Layout, Attribute> sd = standardDefs;
 163         define(sd, ATTR_CONTEXT_CLASS, "Signature", "RSH");
 164         define(sd, ATTR_CONTEXT_CLASS, "Synthetic", "");
 165         define(sd, ATTR_CONTEXT_CLASS, "Deprecated", "");
 166         define(sd, ATTR_CONTEXT_CLASS, "SourceFile", "RUH");
 167         define(sd, ATTR_CONTEXT_CLASS, "EnclosingMethod", "RCHRDNH");
 168         define(sd, ATTR_CONTEXT_CLASS, "InnerClasses", "NH[RCHRCNHRUNHFH]");
 169         define(sd, ATTR_CONTEXT_CLASS, "BootstrapMethods", "NH[RMHNH[KLH]]");
 170 
 171         define(sd, ATTR_CONTEXT_FIELD, "Signature", "RSH");
 172         define(sd, ATTR_CONTEXT_FIELD, "Synthetic", "");
 173         define(sd, ATTR_CONTEXT_FIELD, "Deprecated", "");
 174         define(sd, ATTR_CONTEXT_FIELD, "ConstantValue", "KQH");
 175 
 176         define(sd, ATTR_CONTEXT_METHOD, "Signature", "RSH");
 177         define(sd, ATTR_CONTEXT_METHOD, "Synthetic", "");
 178         define(sd, ATTR_CONTEXT_METHOD, "Deprecated", "");
 179         define(sd, ATTR_CONTEXT_METHOD, "Exceptions", "NH[RCH]");
 180         //define(sd, ATTR_CONTEXT_METHOD, "Code", "HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]");
 181 
 182         define(sd, ATTR_CONTEXT_CODE, "StackMapTable",
 183                ("[NH[(1)]]" +
 184                 "[TB" +
 185                 "(64-127)[(2)]" +
 186                 "(247)[(1)(2)]" +
 187                 "(248-251)[(1)]" +
 188                 "(252)[(1)(2)]" +
 189                 "(253)[(1)(2)(2)]" +
 190                 "(254)[(1)(2)(2)(2)]" +
 191                 "(255)[(1)NH[(2)]NH[(2)]]" +
 192                 "()[]" +
 193                 "]" +
 194                 "[H]" +
 195                 "[TB(7)[RCH](8)[PH]()[]]"));
 196 
 197         define(sd, ATTR_CONTEXT_CODE, "LineNumberTable", "NH[PHH]");
 198         define(sd, ATTR_CONTEXT_CODE, "LocalVariableTable", "NH[PHOHRUHRSHH]");
 199         define(sd, ATTR_CONTEXT_CODE, "LocalVariableTypeTable", "NH[PHOHRUHRSHH]");
 200         //define(sd, ATTR_CONTEXT_CODE, "CharacterRangeTable", "NH[PHPOHIIH]");
 201         //define(sd, ATTR_CONTEXT_CODE, "CoverageTable", "NH[PHHII]");
 202 
 203         // Note:  Code and InnerClasses are special-cased elsewhere.
 204         // Their layout specs. are given here for completeness.
 205         // The Code spec is incomplete, in that it does not distinguish
 206         // bytecode bytes or locate CP references.
 207         // The BootstrapMethods attribute is also special-cased
 208         // elsewhere as an appendix to the local constant pool.
 209     }
 210 
 211     // Metadata.
 212     //
 213     // We define metadata using similar layouts
 214     // for all five kinds of metadata attributes.
 215     //
 216     // Regular annotations are a counted list of [RSHNH[RUH(1)]][...]
 217     //   pack.method.attribute.RuntimeVisibleAnnotations=[NH[(1)]][RSHNH[RUH(1)]][TB...]
 218     //
 219     // Parameter annotations are a counted list of regular annotations.
 220     //   pack.method.attribute.RuntimeVisibleParameterAnnotations=[NH[(1)]][NH[(1)]][RSHNH[RUH(1)]][TB...]
 221     //
 222     // RuntimeInvisible annotations are defined similarly...
 223     // Non-method annotations are defined similarly...
 224     //
 225     // Annotation are a simple tagged value [TB...]
 226     //   pack.attribute.method.AnnotationDefault=[TB...]
 227     //
 228     static {
 229         String mdLayouts[] = {
 230             Attribute.normalizeLayoutString
 231             (""
 232              +"\n  # parameter_annotations :="
 233              +"\n  [ NB[(1)] ]     # forward call to annotations"
 234              ),
 235             Attribute.normalizeLayoutString
 236             (""
 237              +"\n  # annotations :="
 238              +"\n  [ NH[(1)] ]     # forward call to annotation"
 239              +"\n  "
 240              +"\n  # annotation :="
 241              +"\n  [RSH"
 242              +"\n    NH[RUH (1)]   # forward call to value"
 243              +"\n    ]"
 244              ),
 245             Attribute.normalizeLayoutString
 246             (""
 247              +"\n  # value :="
 248              +"\n  [TB # Callable 2 encodes one tagged value."
 249              +"\n    (\\B,\\C,\\I,\\S,\\Z)[KIH]"
 250              +"\n    (\\D)[KDH]"
 251              +"\n    (\\F)[KFH]"
 252              +"\n    (\\J)[KJH]"
 253              +"\n    (\\c)[RSH]"
 254              +"\n    (\\e)[RSH RUH]"
 255              +"\n    (\\s)[RUH]"
 256              +"\n    (\\[)[NH[(0)]] # backward self-call to value"
 257              +"\n    (\\@)[RSH NH[RUH (0)]] # backward self-call to value"
 258              +"\n    ()[] ]"
 259              )
 260         };
 261         Map<Layout, Attribute> sd = standardDefs;
 262         String defaultLayout     = mdLayouts[2];
 263         String annotationsLayout = mdLayouts[1] + mdLayouts[2];
 264         String paramsLayout      = mdLayouts[0] + annotationsLayout;
 265         for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) {
 266             if (ctype == ATTR_CONTEXT_CODE)  continue;
 267             define(sd, ctype,
 268                    "RuntimeVisibleAnnotations",   annotationsLayout);
 269             define(sd, ctype,
 270                    "RuntimeInvisibleAnnotations", annotationsLayout);
 271             if (ctype == ATTR_CONTEXT_METHOD) {
 272                 define(sd, ctype,
 273                        "RuntimeVisibleParameterAnnotations",   paramsLayout);
 274                 define(sd, ctype,
 275                        "RuntimeInvisibleParameterAnnotations", paramsLayout);
 276                 define(sd, ctype,
 277                        "AnnotationDefault", defaultLayout);
 278             }
 279         }
 280     }
 281 
 282     public static String contextName(int ctype) {
 283         switch (ctype) {
 284         case ATTR_CONTEXT_CLASS: return "class";
 285         case ATTR_CONTEXT_FIELD: return "field";
 286         case ATTR_CONTEXT_METHOD: return "method";
 287         case ATTR_CONTEXT_CODE: return "code";
 288         }
 289         return null;
 290     }
 291 
 292     /** Base class for any attributed object (Class, Field, Method, Code).
 293      *  Flags are included because they are used to help transmit the
 294      *  presence of attributes.  That is, flags are a mix of modifier
 295      *  bits and attribute indicators.
 296      */
 297     public static abstract
 298     class Holder {
 299 
 300         // We need this abstract method to interpret embedded CP refs.
 301         protected abstract Entry[] getCPMap();
 302 
 303         protected int flags;             // defined here for convenience
 304         protected List<Attribute> attributes;
 305 
 306         public int attributeSize() {
 307             return (attributes == null) ? 0 : attributes.size();
 308         }
 309 
 310         public void trimToSize() {
 311             if (attributes == null) {
 312                 return;
 313             }
 314             if (attributes.isEmpty()) {
 315                 attributes = null;
 316                 return;
 317             }
 318             if (attributes instanceof ArrayList) {
 319                 ArrayList<Attribute> al = (ArrayList<Attribute>)attributes;
 320                 al.trimToSize();
 321                 boolean allCanon = true;
 322                 for (Attribute a : al) {
 323                     if (!a.isCanonical()) {
 324                         allCanon = false;
 325                     }
 326                     if (a.fixups != null) {
 327                         assert(!a.isCanonical());
 328                         a.fixups = Fixups.trimToSize(a.fixups);
 329                     }
 330                 }
 331                 if (allCanon) {
 332                     // Replace private writable attribute list
 333                     // with only trivial entries by public unique
 334                     // immutable attribute list with the same entries.
 335                     attributes = getCanonList(al);
 336                 }
 337             }
 338         }
 339 
 340         public void addAttribute(Attribute a) {
 341             if (attributes == null)
 342                 attributes = new ArrayList<>(3);
 343             else if (!(attributes instanceof ArrayList))
 344                 attributes = new ArrayList<>(attributes);  // unfreeze it
 345             attributes.add(a);
 346         }
 347 
 348         public Attribute removeAttribute(Attribute a) {
 349             if (attributes == null)       return null;
 350             if (!attributes.contains(a))  return null;
 351             if (!(attributes instanceof ArrayList))
 352                 attributes = new ArrayList<>(attributes);  // unfreeze it
 353             attributes.remove(a);
 354             return a;
 355         }
 356 
 357         public Attribute getAttribute(int n) {
 358             return attributes.get(n);
 359         }
 360 
 361         protected void visitRefs(int mode, Collection<Entry> refs) {
 362             if (attributes == null)  return;
 363             for (Attribute a : attributes) {
 364                 a.visitRefs(this, mode, refs);
 365             }
 366         }
 367 
 368         static final List<Attribute> noAttributes = Arrays.asList(new Attribute[0]);
 369 
 370         public List<Attribute> getAttributes() {
 371             if (attributes == null)
 372                 return noAttributes;
 373             return attributes;
 374         }
 375 
 376         public void setAttributes(List<Attribute> attrList) {
 377             if (attrList.isEmpty())
 378                 attributes = null;
 379             else
 380                 attributes = attrList;
 381         }
 382 
 383         public Attribute getAttribute(String attrName) {
 384             if (attributes == null)  return null;
 385             for (Attribute a : attributes) {
 386                 if (a.name().equals(attrName))
 387                     return a;
 388             }
 389             return null;
 390         }
 391 
 392         public Attribute getAttribute(Layout attrDef) {
 393             if (attributes == null)  return null;
 394             for (Attribute a : attributes) {
 395                 if (a.layout() == attrDef)
 396                     return a;
 397             }
 398             return null;
 399         }
 400 
 401         public Attribute removeAttribute(String attrName) {
 402             return removeAttribute(getAttribute(attrName));
 403         }
 404 
 405         public Attribute removeAttribute(Layout attrDef) {
 406             return removeAttribute(getAttribute(attrDef));
 407         }
 408 
 409         public void strip(String attrName) {
 410             removeAttribute(getAttribute(attrName));
 411         }
 412     }
 413 
 414     // Lightweight interface to hide details of band structure.
 415     // Also used for testing.
 416     public static abstract
 417     class ValueStream {
 418         public int getInt(int bandIndex) { throw undef(); }
 419         public void putInt(int bandIndex, int value) { throw undef(); }
 420         public Entry getRef(int bandIndex) { throw undef(); }
 421         public void putRef(int bandIndex, Entry ref) { throw undef(); }
 422         // Note:  decodeBCI goes w/ getInt/Ref; encodeBCI goes w/ putInt/Ref
 423         public int decodeBCI(int bciCode) { throw undef(); }
 424         public int encodeBCI(int bci) { throw undef(); }
 425         public void noteBackCall(int whichCallable) { /* ignore by default */ }
 426         private RuntimeException undef() {
 427             return new UnsupportedOperationException("ValueStream method");
 428         }
 429     }
 430 
 431     // Element kinds:
 432     static final byte EK_INT  = 1;     // B H I SH etc.
 433     static final byte EK_BCI  = 2;     // PH POH etc.
 434     static final byte EK_BCO  = 3;     // OH etc.
 435     static final byte EK_FLAG = 4;     // FH etc.
 436     static final byte EK_REPL = 5;     // NH[...] etc.
 437     static final byte EK_REF  = 6;     // RUH, RUNH, KQH, etc.
 438     static final byte EK_UN   = 7;     // TB(...)[...] etc.
 439     static final byte EK_CASE = 8;     // (...)[...] etc.
 440     static final byte EK_CALL = 9;     // (0), (1), etc.
 441     static final byte EK_CBLE = 10;    // [...][...] etc.
 442     static final byte EF_SIGN  = 1<<0;   // INT is signed
 443     static final byte EF_DELTA = 1<<1;   // BCI/BCI value is diff'ed w/ previous
 444     static final byte EF_NULL  = 1<<2;   // null REF is expected/allowed
 445     static final byte EF_BACK  = 1<<3;   // call, callable, case is backward
 446     static final int NO_BAND_INDEX = -1;
 447 
 448     /** A "class" of attributes, characterized by a context-type, name
 449      *  and format.  The formats are specified in a "little language".
 450      */
 451     public static
 452     class Layout implements Comparable<Layout> {
 453         int ctype;       // attribute context type, e.g., ATTR_CONTEXT_CODE
 454         String name;     // name of attribute
 455         boolean hasRefs; // this kind of attr contains CP refs?
 456         String layout;   // layout specification
 457         int bandCount;   // total number of elems
 458         Element[] elems; // tokenization of layout
 459         Attribute canon; // canonical instance of this layout
 460 
 461         public int ctype() { return ctype; }
 462         public String name() { return name; }
 463         public String layout() { return layout; }
 464         public Attribute canonicalInstance() { return canon; }
 465 
 466         public Entry getNameRef() {
 467             return ConstantPool.getUtf8Entry(name());
 468         }
 469 
 470         public boolean isEmpty() {
 471             return layout.isEmpty();
 472         }
 473 
 474         public Layout(int ctype, String name, String layout) {
 475             this.ctype = ctype;
 476             this.name = name.intern();
 477             this.layout = layout.intern();
 478             assert(ctype < ATTR_CONTEXT_LIMIT);
 479             boolean hasCallables = layout.startsWith("[");
 480             try {
 481                 if (!hasCallables) {
 482                     this.elems = tokenizeLayout(this, -1, layout);
 483                 } else {
 484                     String[] bodies = splitBodies(layout);
 485                     // Make the callables now, so they can be linked immediately.
 486                     Element[] lelems = new Element[bodies.length];
 487                     this.elems = lelems;
 488                     for (int i = 0; i < lelems.length; i++) {
 489                         Element ce = this.new Element();
 490                         ce.kind = EK_CBLE;
 491                         ce.removeBand();
 492                         ce.bandIndex = NO_BAND_INDEX;
 493                         ce.layout = bodies[i];
 494                         lelems[i] = ce;
 495                     }
 496                     // Next fill them in.
 497                     for (int i = 0; i < lelems.length; i++) {
 498                         Element ce = lelems[i];
 499                         ce.body = tokenizeLayout(this, i, bodies[i]);
 500                     }
 501                     //System.out.println(Arrays.asList(elems));
 502                 }
 503             } catch (StringIndexOutOfBoundsException ee) {
 504                 // simplest way to catch syntax errors...
 505                 throw new RuntimeException("Bad attribute layout: "+layout, ee);
 506             }
 507             // Some uses do not make a fresh one for each occurrence.
 508             // For example, if layout == "", we only need one attr to share.
 509             canon = new Attribute(this, noBytes);
 510         }
 511         private Layout() {}
 512         static Layout makeKey(int ctype, String name, String layout) {
 513             Layout def = new Layout();
 514             def.ctype = ctype;
 515             def.name = name.intern();
 516             def.layout = layout.intern();
 517             assert(ctype < ATTR_CONTEXT_LIMIT);
 518             return def;
 519         }
 520         static Layout makeKey(int ctype, String name) {
 521             return makeKey(ctype, name, "");
 522         }
 523 
 524         public Attribute addContent(byte[] bytes, Object fixups) {
 525             return canon.addContent(bytes, fixups);
 526         }
 527         public Attribute addContent(byte[] bytes) {
 528             return canon.addContent(bytes, null);
 529         }
 530 
 531         public boolean equals(Object x) {
 532             return ( x != null) && ( x.getClass() == Layout.class ) &&
 533                     equals((Layout)x);
 534         }
 535         public boolean equals(Layout that) {
 536             return this.name.equals(that.name)
 537                 && this.layout.equals(that.layout)
 538                 && this.ctype == that.ctype;
 539         }
 540         public int hashCode() {
 541             return (((17 + name.hashCode())
 542                     * 37 + layout.hashCode())
 543                     * 37 + ctype);
 544         }
 545         public int compareTo(Layout that) {
 546             int r;
 547             r = this.name.compareTo(that.name);
 548             if (r != 0)  return r;
 549             r = this.layout.compareTo(that.layout);
 550             if (r != 0)  return r;
 551             return this.ctype - that.ctype;
 552         }
 553         public String toString() {
 554             String str = contextName(ctype)+"."+name+"["+layout+"]";
 555             // If -ea, print out more informative strings!
 556             assert((str = stringForDebug()) != null);
 557             return str;
 558         }
 559         private String stringForDebug() {
 560             return contextName(ctype)+"."+name+Arrays.asList(elems);
 561         }
 562 
 563         public
 564         class Element {
 565             String layout;   // spelling in the little language
 566             byte flags;      // EF_SIGN, etc.
 567             byte kind;       // EK_UINT, etc.
 568             byte len;        // scalar length of element
 569             byte refKind;    // CONSTANT_String, etc.
 570             int bandIndex;   // which band does this element govern?
 571             int value;       // extra parameter
 572             Element[] body;  // extra data (for replications, unions, calls)
 573 
 574             boolean flagTest(byte mask) { return (flags & mask) != 0; }
 575 
 576             Element() {
 577                 bandIndex = bandCount++;
 578             }
 579 
 580             void removeBand() {
 581                 --bandCount;
 582                 assert(bandIndex == bandCount);
 583                 bandIndex = NO_BAND_INDEX;
 584             }
 585 
 586             public boolean hasBand() {
 587                 return bandIndex >= 0;
 588             }
 589             public String toString() {
 590                 String str = layout;
 591                 // If -ea, print out more informative strings!
 592                 assert((str = stringForDebug()) != null);
 593                 return str;
 594             }
 595             private String stringForDebug() {
 596                 Element[] lbody = this.body;
 597                 switch (kind) {
 598                 case EK_CALL:
 599                     lbody = null;
 600                     break;
 601                 case EK_CASE:
 602                     if (flagTest(EF_BACK))
 603                         lbody = null;
 604                     break;
 605                 }
 606                 return layout
 607                     + (!hasBand()?"":"#"+bandIndex)
 608                     + "<"+ (flags==0?"":""+flags)+kind+len
 609                     + (refKind==0?"":""+refKind) + ">"
 610                     + (value==0?"":"("+value+")")
 611                     + (lbody==null?"": ""+Arrays.asList(lbody));
 612             }
 613         }
 614 
 615         public boolean hasCallables() {
 616             return (elems.length > 0 && elems[0].kind == EK_CBLE);
 617         }
 618         static private final Element[] noElems = {};
 619         public Element[] getCallables() {
 620             if (hasCallables()) {
 621                 Element[] nelems = Arrays.copyOf(elems, elems.length);
 622                 return nelems;
 623             } else
 624                 return noElems;  // no callables at all
 625         }
 626         public Element[] getEntryPoint() {
 627             if (hasCallables())
 628                 return elems[0].body;  // body of first callable
 629             else {
 630                 Element[] nelems = Arrays.copyOf(elems, elems.length);
 631                 return nelems;  // no callables; whole body
 632             }
 633         }
 634 
 635         /** Return a sequence of tokens from the given attribute bytes.
 636          *  Sequence elements will be 1-1 correspondent with my layout tokens.
 637          */
 638         public void parse(Holder holder,
 639                           byte[] bytes, int pos, int len, ValueStream out) {
 640             int end = parseUsing(getEntryPoint(),
 641                                  holder, bytes, pos, len, out);
 642             if (end != pos + len)
 643                 throw new InternalError("layout parsed "+(end-pos)+" out of "+len+" bytes");
 644         }
 645         /** Given a sequence of tokens, return the attribute bytes.
 646          *  Sequence elements must be 1-1 correspondent with my layout tokens.
 647          *  The returned object is a cookie for Fixups.finishRefs, which
 648          *  must be used to harden any references into integer indexes.
 649          */
 650         public Object unparse(ValueStream in, ByteArrayOutputStream out) {
 651             Object[] fixups = { null };
 652             unparseUsing(getEntryPoint(), fixups, in, out);
 653             return fixups[0]; // return ref-bearing cookie, if any
 654         }
 655 
 656         public String layoutForClassVersion(Package.Version vers) {
 657             if (vers.lessThan(JAVA6_MAX_CLASS_VERSION)) {
 658                 // Disallow layout syntax in the oldest protocol version.
 659                 return expandCaseDashNotation(layout);
 660             }
 661             return layout;
 662         }
 663     }
 664 
 665     public static
 666     class FormatException extends IOException {
 667         private static final long serialVersionUID = -2542243830788066513L;
 668 
 669         private int ctype;
 670         private String name;
 671         String layout;
 672         public FormatException(String message,
 673                                int ctype, String name, String layout) {
 674             super(ATTR_CONTEXT_NAME[ctype]+ " attribute \"" + name + "\"" +
 675                   (message == null? "" : (": " + message)));
 676             this.ctype = ctype;
 677             this.name = name;
 678             this.layout = layout;
 679         }
 680         public FormatException(String message,
 681                                int ctype, String name) {
 682             this(message, ctype, name, null);
 683         }
 684     }
 685 
 686     void visitRefs(Holder holder, int mode, final Collection<Entry> refs) {
 687         if (mode == VRM_CLASSIC) {
 688             refs.add(getNameRef());
 689         }
 690         // else the name is owned by the layout, and is processed elsewhere
 691         if (bytes.length == 0)  return;  // quick exit
 692         if (!def.hasRefs)       return;  // quick exit
 693         if (fixups != null) {
 694             Fixups.visitRefs(fixups, refs);
 695             return;
 696         }
 697         // References (to a local cpMap) are embedded in the bytes.
 698         def.parse(holder, bytes, 0, bytes.length,
 699             new ValueStream() {
 700                 public void putInt(int bandIndex, int value) {
 701                 }
 702                 public void putRef(int bandIndex, Entry ref) {
 703                     refs.add(ref);
 704                 }
 705                 public int encodeBCI(int bci) {
 706                     return bci;
 707                 }
 708             });
 709     }
 710 
 711     public void parse(Holder holder, byte[] bytes, int pos, int len, ValueStream out) {
 712         def.parse(holder, bytes, pos, len, out);
 713     }
 714     public Object unparse(ValueStream in, ByteArrayOutputStream out) {
 715         return def.unparse(in, out);
 716     }
 717 
 718     public String toString() {
 719         return def
 720             +"{"+(bytes == null ? -1 : size())+"}"
 721             +(fixups == null? "": fixups.toString());
 722     }
 723 
 724     /** Remove any informal "pretty printing" from the layout string.
 725      *  Removes blanks and control chars.
 726      *  Removes '#' comments (to end of line).
 727      *  Replaces '\c' by the decimal code of the character c.
 728      *  Replaces '0xNNN' by the decimal code of the hex number NNN.
 729      */
 730     static public
 731     String normalizeLayoutString(String layout) {
 732         StringBuilder buf = new StringBuilder();
 733         for (int i = 0, len = layout.length(); i < len; ) {
 734             char ch = layout.charAt(i++);
 735             if (ch <= ' ') {
 736                 // Skip whitespace and control chars
 737                 continue;
 738             } else if (ch == '#') {
 739                 // Skip to end of line.
 740                 int end1 = layout.indexOf('\n', i);
 741                 int end2 = layout.indexOf('\r', i);
 742                 if (end1 < 0)  end1 = len;
 743                 if (end2 < 0)  end2 = len;
 744                 i = Math.min(end1, end2);
 745             } else if (ch == '\\') {
 746                 // Map a character reference to its decimal code.
 747                 buf.append((int) layout.charAt(i++));
 748             } else if (ch == '0' && layout.startsWith("0x", i-1)) {
 749                 // Map a hex numeral to its decimal code.
 750                 int start = i-1;
 751                 int end = start+2;
 752                 while (end < len) {
 753                     int dig = layout.charAt(end);
 754                     if ((dig >= '0' && dig <= '9') ||
 755                         (dig >= 'a' && dig <= 'f'))
 756                         ++end;
 757                     else
 758                         break;
 759                 }
 760                 if (end > start) {
 761                     String num = layout.substring(start, end);
 762                     buf.append(Integer.decode(num));
 763                     i = end;
 764                 } else {
 765                     buf.append(ch);
 766                 }
 767             } else {
 768                 buf.append(ch);
 769             }
 770         }
 771         String result = buf.toString();
 772         if (false && !result.equals(layout)) {
 773             Utils.log.info("Normalizing layout string");
 774             Utils.log.info("    From: "+layout);
 775             Utils.log.info("    To:   "+result);
 776         }
 777         return result;
 778     }
 779 
 780     /// Subroutines for parsing and unparsing:
 781 
 782     /** Parse the attribute layout language.
 783 <pre>
 784   attribute_layout:
 785         ( layout_element )* | ( callable )+
 786   layout_element:
 787         ( integral | replication | union | call | reference )
 788 
 789   callable:
 790         '[' body ']'
 791   body:
 792         ( layout_element )+
 793 
 794   integral:
 795         ( unsigned_int | signed_int | bc_index | bc_offset | flag )
 796   unsigned_int:
 797         uint_type
 798   signed_int:
 799         'S' uint_type
 800   any_int:
 801         ( unsigned_int | signed_int )
 802   bc_index:
 803         ( 'P' uint_type | 'PO' uint_type )
 804   bc_offset:
 805         'O' any_int
 806   flag:
 807         'F' uint_type
 808   uint_type:
 809         ( 'B' | 'H' | 'I' | 'V' )
 810 
 811   replication:
 812         'N' uint_type '[' body ']'
 813 
 814   union:
 815         'T' any_int (union_case)* '(' ')' '[' (body)? ']'
 816   union_case:
 817         '(' union_case_tag (',' union_case_tag)* ')' '[' (body)? ']'
 818   union_case_tag:
 819         ( numeral | numeral '-' numeral )
 820   call:
 821         '(' numeral ')'
 822 
 823   reference:
 824         reference_type ( 'N' )? uint_type
 825   reference_type:
 826         ( constant_ref | schema_ref | utf8_ref | untyped_ref )
 827   constant_ref:
 828         ( 'KI' | 'KJ' | 'KF' | 'KD' | 'KS' | 'KQ' | 'KM' | 'KT' | 'KL' )
 829   schema_ref:
 830         ( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' | 'RY' | 'RB' | 'RN' )
 831   utf8_ref:
 832         'RU'
 833   untyped_ref:
 834         'RQ'
 835 
 836   numeral:
 837         '(' ('-')? (digit)+ ')'
 838   digit:
 839         ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
 840  </pre>
 841     */
 842     static //private
 843     Layout.Element[] tokenizeLayout(Layout self, int curCble, String layout) {
 844         List<Layout.Element> col = new ArrayList<>(layout.length());
 845         tokenizeLayout(self, curCble, layout, col);
 846         Layout.Element[] res = new Layout.Element[col.size()];
 847         col.toArray(res);
 848         return res;
 849     }
 850     static //private
 851     void tokenizeLayout(Layout self, int curCble, String layout, List<Layout.Element> col) {
 852         boolean prevBCI = false;
 853         for (int len = layout.length(), i = 0; i < len; ) {
 854             int start = i;
 855             int body;
 856             Layout.Element e = self.new Element();
 857             byte kind;
 858             //System.out.println("at "+i+": ..."+layout.substring(i));
 859             // strip a prefix
 860             switch (layout.charAt(i++)) {
 861             /// layout_element: integral
 862             case 'B': case 'H': case 'I': case 'V': // unsigned_int
 863                 kind = EK_INT;
 864                 --i; // reparse
 865                 i = tokenizeUInt(e, layout, i);
 866                 break;
 867             case 'S': // signed_int
 868                 kind = EK_INT;
 869                 --i; // reparse
 870                 i = tokenizeSInt(e, layout, i);
 871                 break;
 872             case 'P': // bc_index
 873                 kind = EK_BCI;
 874                 if (layout.charAt(i++) == 'O') {
 875                     // bc_index: 'PO' tokenizeUInt
 876                     e.flags |= EF_DELTA;
 877                     // must follow P or PO:
 878                     if (!prevBCI)
 879                         { i = -i; continue; } // fail
 880                     i++; // move forward
 881                 }
 882                 --i; // reparse
 883                 i = tokenizeUInt(e, layout, i);
 884                 break;
 885             case 'O': // bc_offset
 886                 kind = EK_BCO;
 887                 e.flags |= EF_DELTA;
 888                 // must follow P or PO:
 889                 if (!prevBCI)
 890                     { i = -i; continue; } // fail
 891                 i = tokenizeSInt(e, layout, i);
 892                 break;
 893             case 'F': // flag
 894                 kind = EK_FLAG;
 895                 i = tokenizeUInt(e, layout, i);
 896                 break;
 897             case 'N': // replication: 'N' uint '[' elem ... ']'
 898                 kind = EK_REPL;
 899                 i = tokenizeUInt(e, layout, i);
 900                 if (layout.charAt(i++) != '[')
 901                     { i = -i; continue; } // fail
 902                 i = skipBody(layout, body = i);
 903                 e.body = tokenizeLayout(self, curCble,
 904                                         layout.substring(body, i++));
 905                 break;
 906             case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']'
 907                 kind = EK_UN;
 908                 i = tokenizeSInt(e, layout, i);
 909                 List<Layout.Element> cases = new ArrayList<>();
 910                 for (;;) {
 911                     // Keep parsing cases until we hit the default case.
 912                     if (layout.charAt(i++) != '(')
 913                         { i = -i; break; } // fail
 914                     int beg = i;
 915                     i = layout.indexOf(')', i);
 916                     String cstr = layout.substring(beg, i++);
 917                     int cstrlen = cstr.length();
 918                     if (layout.charAt(i++) != '[')
 919                         { i = -i; break; } // fail
 920                     // Check for duplication.
 921                     if (layout.charAt(i) == ']')
 922                         body = i;  // missing body, which is legal here
 923                     else
 924                         i = skipBody(layout, body = i);
 925                     Layout.Element[] cbody
 926                         = tokenizeLayout(self, curCble,
 927                                          layout.substring(body, i++));
 928                     if (cstrlen == 0) {
 929                         Layout.Element ce = self.new Element();
 930                         ce.body = cbody;
 931                         ce.kind = EK_CASE;
 932                         ce.removeBand();
 933                         cases.add(ce);
 934                         break;  // done with the whole union
 935                     } else {
 936                         // Parse a case string.
 937                         boolean firstCaseNum = true;
 938                         for (int cp = 0, endp;; cp = endp+1) {
 939                             // Look for multiple case tags:
 940                             endp = cstr.indexOf(',', cp);
 941                             if (endp < 0)  endp = cstrlen;
 942                             String cstr1 = cstr.substring(cp, endp);
 943                             if (cstr1.length() == 0)
 944                                 cstr1 = "empty";  // will fail parse
 945                             int value0, value1;
 946                             // Check for a case range (new in 1.6).
 947                             int dash = findCaseDash(cstr1, 0);
 948                             if (dash >= 0) {
 949                                 value0 = parseIntBefore(cstr1, dash);
 950                                 value1 = parseIntAfter(cstr1, dash);
 951                                 if (value0 >= value1)
 952                                     { i = -i; break; } // fail
 953                             } else {
 954                                 value0 = value1 = Integer.parseInt(cstr1);
 955                             }
 956                             // Add a case for each value in value0..value1
 957                             for (;; value0++) {
 958                                 Layout.Element ce = self.new Element();
 959                                 ce.body = cbody;  // all cases share one body
 960                                 ce.kind = EK_CASE;
 961                                 ce.removeBand();
 962                                 if (!firstCaseNum)
 963                                     // "backward case" repeats a body
 964                                     ce.flags |= EF_BACK;
 965                                 firstCaseNum = false;
 966                                 ce.value = value0;
 967                                 cases.add(ce);
 968                                 if (value0 == value1)  break;
 969                             }
 970                             if (endp == cstrlen) {
 971                                 break;  // done with this case
 972                             }
 973                         }
 974                     }
 975                 }
 976                 e.body = new Layout.Element[cases.size()];
 977                 cases.toArray(e.body);
 978                 e.kind = kind;
 979                 for (int j = 0; j < e.body.length-1; j++) {
 980                     Layout.Element ce = e.body[j];
 981                     if (matchCase(e, ce.value) != ce) {
 982                         // Duplicate tag.
 983                         { i = -i; break; } // fail
 984                     }
 985                 }
 986                 break;
 987             case '(': // call: '(' '-'? digit+ ')'
 988                 kind = EK_CALL;
 989                 e.removeBand();
 990                 i = layout.indexOf(')', i);
 991                 String cstr = layout.substring(start+1, i++);
 992                 int offset = Integer.parseInt(cstr);
 993                 int target = curCble + offset;
 994                 if (!(offset+"").equals(cstr) ||
 995                     self.elems == null ||
 996                     target < 0 ||
 997                     target >= self.elems.length)
 998                     { i = -i; continue; } // fail
 999                 Layout.Element ce = self.elems[target];
1000                 assert(ce.kind == EK_CBLE);
1001                 e.value = target;
1002                 e.body = new Layout.Element[]{ ce };
1003                 // Is it a (recursive) backward call?
1004                 if (offset <= 0) {
1005                     // Yes.  Mark both caller and callee backward.
1006                     e.flags  |= EF_BACK;
1007                     ce.flags |= EF_BACK;
1008                 }
1009                 break;
1010             case 'K':  // reference_type: constant_ref
1011                 kind = EK_REF;
1012                 switch (layout.charAt(i++)) {
1013                 case 'I': e.refKind = CONSTANT_Integer; break;
1014                 case 'J': e.refKind = CONSTANT_Long; break;
1015                 case 'F': e.refKind = CONSTANT_Float; break;
1016                 case 'D': e.refKind = CONSTANT_Double; break;
1017                 case 'S': e.refKind = CONSTANT_String; break;
1018                 case 'Q': e.refKind = CONSTANT_FieldSpecific; break;
1019 
1020                 // new in 1.7:
1021                 case 'M': e.refKind = CONSTANT_MethodHandle; break;
1022                 case 'T': e.refKind = CONSTANT_MethodType; break;
1023                 case 'L': e.refKind = CONSTANT_LoadableValue; break;
1024                 default: { i = -i; continue; } // fail
1025                 }
1026                 break;
1027             case 'R': // schema_ref
1028                 kind = EK_REF;
1029                 switch (layout.charAt(i++)) {
1030                 case 'C': e.refKind = CONSTANT_Class; break;
1031                 case 'S': e.refKind = CONSTANT_Signature; break;
1032                 case 'D': e.refKind = CONSTANT_NameandType; break;
1033                 case 'F': e.refKind = CONSTANT_Fieldref; break;
1034                 case 'M': e.refKind = CONSTANT_Methodref; break;
1035                 case 'I': e.refKind = CONSTANT_InterfaceMethodref; break;
1036 
1037                 case 'U': e.refKind = CONSTANT_Utf8; break; //utf8_ref
1038                 case 'Q': e.refKind = CONSTANT_All; break; //untyped_ref
1039 
1040                 // new in 1.7:
1041                 case 'Y': e.refKind = CONSTANT_InvokeDynamic; break;
1042                 case 'B': e.refKind = CONSTANT_BootstrapMethod; break;
1043                 case 'N': e.refKind = CONSTANT_AnyMember; break;
1044 
1045                 default: { i = -i; continue; } // fail
1046                 }
1047                 break;
1048             default: { i = -i; continue; } // fail
1049             }
1050 
1051             // further parsing of refs
1052             if (kind == EK_REF) {
1053                 // reference: reference_type -><- ( 'N' )? tokenizeUInt
1054                 if (layout.charAt(i++) == 'N') {
1055                     e.flags |= EF_NULL;
1056                     i++; // move forward
1057                 }
1058                 --i; // reparse
1059                 i = tokenizeUInt(e, layout, i);
1060                 self.hasRefs = true;
1061             }
1062 
1063             prevBCI = (kind == EK_BCI);
1064 
1065             // store the new element
1066             e.kind = kind;
1067             e.layout = layout.substring(start, i);
1068             col.add(e);
1069         }
1070     }
1071     static //private
1072     String[] splitBodies(String layout) {
1073         List<String> bodies = new ArrayList<>();
1074         // Parse several independent layout bodies:  "[foo][bar]...[baz]"
1075         for (int i = 0; i < layout.length(); i++) {
1076             if (layout.charAt(i++) != '[')
1077                 layout.charAt(-i);  // throw error
1078             int body;
1079             i = skipBody(layout, body = i);
1080             bodies.add(layout.substring(body, i));
1081         }
1082         String[] res = new String[bodies.size()];
1083         bodies.toArray(res);
1084         return res;
1085     }
1086     static private
1087     int skipBody(String layout, int i) {
1088         assert(layout.charAt(i-1) == '[');
1089         if (layout.charAt(i) == ']')
1090             // No empty bodies, please.
1091             return -i;
1092         // skip balanced [...[...]...]
1093         for (int depth = 1; depth > 0; ) {
1094             switch (layout.charAt(i++)) {
1095             case '[': depth++; break;
1096             case ']': depth--; break;
1097             }
1098         }
1099         --i;  // get before bracket
1100         assert(layout.charAt(i) == ']');
1101         return i;  // return closing bracket
1102     }
1103     static private
1104     int tokenizeUInt(Layout.Element e, String layout, int i) {
1105         switch (layout.charAt(i++)) {
1106         case 'V': e.len = 0; break;
1107         case 'B': e.len = 1; break;
1108         case 'H': e.len = 2; break;
1109         case 'I': e.len = 4; break;
1110         default: return -i;
1111         }
1112         return i;
1113     }
1114     static private
1115     int tokenizeSInt(Layout.Element e, String layout, int i) {
1116         if (layout.charAt(i) == 'S') {
1117             e.flags |= EF_SIGN;
1118             ++i;
1119         }
1120         return tokenizeUInt(e, layout, i);
1121     }
1122 
1123     static private
1124     boolean isDigit(char c) {
1125         return c >= '0' && c <= '9';
1126     }
1127 
1128     /** Find an occurrence of hyphen '-' between two numerals. */
1129     static //private
1130     int findCaseDash(String layout, int fromIndex) {
1131         if (fromIndex <= 0)  fromIndex = 1;  // minimum dash pos
1132         int lastDash = layout.length() - 2;  // maximum dash pos
1133         for (;;) {
1134             int dash = layout.indexOf('-', fromIndex);
1135             if (dash < 0 || dash > lastDash)  return -1;
1136             if (isDigit(layout.charAt(dash-1))) {
1137                 char afterDash = layout.charAt(dash+1);
1138                 if (afterDash == '-' && dash+2 < layout.length())
1139                     afterDash = layout.charAt(dash+2);
1140                 if (isDigit(afterDash)) {
1141                     // matched /[0-9]--?[0-9]/; return position of dash
1142                     return dash;
1143                 }
1144             }
1145             fromIndex = dash+1;
1146         }
1147     }
1148     static
1149     int parseIntBefore(String layout, int dash) {
1150         int end = dash;
1151         int beg = end;
1152         while (beg > 0 && isDigit(layout.charAt(beg-1))) {
1153             --beg;
1154         }
1155         if (beg == end)  return Integer.parseInt("empty");
1156         // skip backward over a sign
1157         if (beg >= 1 && layout.charAt(beg-1) == '-')  --beg;
1158         assert(beg == 0 || !isDigit(layout.charAt(beg-1)));
1159         return Integer.parseInt(layout.substring(beg, end));
1160     }
1161     static
1162     int parseIntAfter(String layout, int dash) {
1163         int beg = dash+1;
1164         int end = beg;
1165         int limit = layout.length();
1166         if (end < limit && layout.charAt(end) == '-')  ++end;
1167         while (end < limit && isDigit(layout.charAt(end))) {
1168             ++end;
1169         }
1170         if (beg == end)  return Integer.parseInt("empty");
1171         return Integer.parseInt(layout.substring(beg, end));
1172     }
1173     /** For compatibility with 1.5 pack, expand 1-5 into 1,2,3,4,5. */
1174     static
1175     String expandCaseDashNotation(String layout) {
1176         int dash = findCaseDash(layout, 0);
1177         if (dash < 0)  return layout;  // no dashes (the common case)
1178         StringBuilder result = new StringBuilder(layout.length() * 3);
1179         int sofar = 0;  // how far have we processed the layout?
1180         for (;;) {
1181             // for each dash, collect everything up to the dash
1182             result.append(layout.substring(sofar, dash));
1183             sofar = dash+1;  // skip the dash
1184             // then collect intermediate values
1185             int value0 = parseIntBefore(layout, dash);
1186             int value1 = parseIntAfter(layout, dash);
1187             assert(value0 < value1);
1188             result.append(",");  // close off value0 numeral
1189             for (int i = value0+1; i < value1; i++) {
1190                 result.append(i);
1191                 result.append(",");  // close off i numeral
1192             }
1193             dash = findCaseDash(layout, sofar);
1194             if (dash < 0)  break;
1195         }
1196         result.append(layout.substring(sofar));  // collect the rest
1197         return result.toString();
1198     }
1199     static {
1200         assert(expandCaseDashNotation("1-5").equals("1,2,3,4,5"));
1201         assert(expandCaseDashNotation("-2--1").equals("-2,-1"));
1202         assert(expandCaseDashNotation("-2-1").equals("-2,-1,0,1"));
1203         assert(expandCaseDashNotation("-1-0").equals("-1,0"));
1204     }
1205 
1206     // Parse attribute bytes, putting values into bands.  Returns new pos.
1207     // Used when reading a class file (local refs resolved with local cpMap).
1208     // Also used for ad hoc scanning.
1209     static
1210     int parseUsing(Layout.Element[] elems, Holder holder,
1211                    byte[] bytes, int pos, int len, ValueStream out) {
1212         int prevBCI = 0;
1213         int prevRBCI = 0;
1214         int end = pos + len;
1215         int[] buf = { 0 };  // for calls to parseInt, holds 2nd result
1216         for (int i = 0; i < elems.length; i++) {
1217             Layout.Element e = elems[i];
1218             int bandIndex = e.bandIndex;
1219             int value;
1220             int BCI, RBCI;
1221             switch (e.kind) {
1222             case EK_INT:
1223                 pos = parseInt(e, bytes, pos, buf);
1224                 value = buf[0];
1225                 out.putInt(bandIndex, value);
1226                 break;
1227             case EK_BCI:  // PH, POH
1228                 pos = parseInt(e, bytes, pos, buf);
1229                 BCI = buf[0];
1230                 RBCI = out.encodeBCI(BCI);
1231                 if (!e.flagTest(EF_DELTA)) {
1232                     // PH:  transmit R(bci), store bci
1233                     value = RBCI;
1234                 } else {
1235                     // POH:  transmit D(R(bci)), store bci
1236                     value = RBCI - prevRBCI;
1237                 }
1238                 prevBCI = BCI;
1239                 prevRBCI = RBCI;
1240                 out.putInt(bandIndex, value);
1241                 break;
1242             case EK_BCO:  // OH
1243                 assert(e.flagTest(EF_DELTA));
1244                 // OH:  transmit D(R(bci)), store D(bci)
1245                 pos = parseInt(e, bytes, pos, buf);
1246                 BCI = prevBCI + buf[0];
1247                 RBCI = out.encodeBCI(BCI);
1248                 value = RBCI - prevRBCI;
1249                 prevBCI = BCI;
1250                 prevRBCI = RBCI;
1251                 out.putInt(bandIndex, value);
1252                 break;
1253             case EK_FLAG:
1254                 pos = parseInt(e, bytes, pos, buf);
1255                 value = buf[0];
1256                 out.putInt(bandIndex, value);
1257                 break;
1258             case EK_REPL:
1259                 pos = parseInt(e, bytes, pos, buf);
1260                 value = buf[0];
1261                 out.putInt(bandIndex, value);
1262                 for (int j = 0; j < value; j++) {
1263                     pos = parseUsing(e.body, holder, bytes, pos, end-pos, out);
1264                 }
1265                 break;  // already transmitted the scalar value
1266             case EK_UN:
1267                 pos = parseInt(e, bytes, pos, buf);
1268                 value = buf[0];
1269                 out.putInt(bandIndex, value);
1270                 Layout.Element ce = matchCase(e, value);
1271                 pos = parseUsing(ce.body, holder, bytes, pos, end-pos, out);
1272 
1273                 break;  // already transmitted the scalar value
1274             case EK_CALL:
1275                 // Adjust band offset if it is a backward call.
1276                 assert(e.body.length == 1);
1277                 assert(e.body[0].kind == EK_CBLE);
1278                 if (e.flagTest(EF_BACK))
1279                     out.noteBackCall(e.value);
1280                 pos = parseUsing(e.body[0].body, holder, bytes, pos, end-pos, out);
1281                 break;  // no additional scalar value to transmit
1282             case EK_REF:
1283                 pos = parseInt(e, bytes, pos, buf);
1284                 int localRef = buf[0];
1285                 Entry globalRef;
1286                 if (localRef == 0) {
1287                     globalRef = null;  // N.B. global null reference is -1
1288                 } else {
1289                     globalRef = holder.getCPMap()[localRef];
1290                     if (e.refKind == CONSTANT_Signature
1291                         && globalRef.getTag() == CONSTANT_Utf8) {
1292                         // Cf. ClassReader.readSignatureRef.
1293                         String typeName = globalRef.stringValue();
1294                         globalRef = ConstantPool.getSignatureEntry(typeName);
1295                     } else if (e.refKind == CONSTANT_FieldSpecific) {
1296                         assert(globalRef.getTag() >= CONSTANT_Integer);
1297                         assert(globalRef.getTag() <= CONSTANT_String ||
1298                                globalRef.getTag() >= CONSTANT_MethodHandle);
1299                         assert(globalRef.getTag() <= CONSTANT_MethodType);
1300                     } else if (e.refKind < CONSTANT_GroupFirst) {
1301                         assert(e.refKind == globalRef.getTag());
1302                     }
1303                 }
1304                 out.putRef(bandIndex, globalRef);
1305                 break;
1306             default: assert(false); continue;
1307             }
1308         }
1309         return pos;
1310     }
1311 
1312     static
1313     Layout.Element matchCase(Layout.Element e, int value) {
1314         assert(e.kind == EK_UN);
1315         int lastj = e.body.length-1;
1316         for (int j = 0; j < lastj; j++) {
1317             Layout.Element ce = e.body[j];
1318             assert(ce.kind == EK_CASE);
1319             if (value == ce.value)
1320                 return ce;
1321         }
1322         return e.body[lastj];
1323     }
1324 
1325     static private
1326     int parseInt(Layout.Element e, byte[] bytes, int pos, int[] buf) {
1327         int value = 0;
1328         int loBits = e.len * 8;
1329         // Read in big-endian order:
1330         for (int bitPos = loBits; (bitPos -= 8) >= 0; ) {
1331             value += (bytes[pos++] & 0xFF) << bitPos;
1332         }
1333         if (loBits < 32 && e.flagTest(EF_SIGN)) {
1334             // sign-extend subword value
1335             int hiBits = 32 - loBits;
1336             value = (value << hiBits) >> hiBits;
1337         }
1338         buf[0] = value;
1339         return pos;
1340     }
1341 
1342     // Format attribute bytes, drawing values from bands.
1343     // Used when emptying attribute bands into a package model.
1344     // (At that point CP refs. are not yet assigned indexes.)
1345     static
1346     void unparseUsing(Layout.Element[] elems, Object[] fixups,
1347                       ValueStream in, ByteArrayOutputStream out) {
1348         int prevBCI = 0;
1349         int prevRBCI = 0;
1350         for (int i = 0; i < elems.length; i++) {
1351             Layout.Element e = elems[i];
1352             int bandIndex = e.bandIndex;
1353             int value;
1354             int BCI, RBCI;  // "RBCI" is R(BCI), BCI's coded representation
1355             switch (e.kind) {
1356             case EK_INT:
1357                 value = in.getInt(bandIndex);
1358                 unparseInt(e, value, out);
1359                 break;
1360             case EK_BCI:  // PH, POH
1361                 value = in.getInt(bandIndex);
1362                 if (!e.flagTest(EF_DELTA)) {
1363                     // PH:  transmit R(bci), store bci
1364                     RBCI = value;
1365                 } else {
1366                     // POH:  transmit D(R(bci)), store bci
1367                     RBCI = prevRBCI + value;
1368                 }
1369                 assert(prevBCI == in.decodeBCI(prevRBCI));
1370                 BCI = in.decodeBCI(RBCI);
1371                 unparseInt(e, BCI, out);
1372                 prevBCI = BCI;
1373                 prevRBCI = RBCI;
1374                 break;
1375             case EK_BCO:  // OH
1376                 value = in.getInt(bandIndex);
1377                 assert(e.flagTest(EF_DELTA));
1378                 // OH:  transmit D(R(bci)), store D(bci)
1379                 assert(prevBCI == in.decodeBCI(prevRBCI));
1380                 RBCI = prevRBCI + value;
1381                 BCI = in.decodeBCI(RBCI);
1382                 unparseInt(e, BCI - prevBCI, out);
1383                 prevBCI = BCI;
1384                 prevRBCI = RBCI;
1385                 break;
1386             case EK_FLAG:
1387                 value = in.getInt(bandIndex);
1388                 unparseInt(e, value, out);
1389                 break;
1390             case EK_REPL:
1391                 value = in.getInt(bandIndex);
1392                 unparseInt(e, value, out);
1393                 for (int j = 0; j < value; j++) {
1394                     unparseUsing(e.body, fixups, in, out);
1395                 }
1396                 break;
1397             case EK_UN:
1398                 value = in.getInt(bandIndex);
1399                 unparseInt(e, value, out);
1400                 Layout.Element ce = matchCase(e, value);
1401                 unparseUsing(ce.body, fixups, in, out);
1402                 break;
1403             case EK_CALL:
1404                 assert(e.body.length == 1);
1405                 assert(e.body[0].kind == EK_CBLE);
1406                 unparseUsing(e.body[0].body, fixups, in, out);
1407                 break;
1408             case EK_REF:
1409                 Entry globalRef = in.getRef(bandIndex);
1410                 int localRef;
1411                 if (globalRef != null) {
1412                     // It's a one-element array, really an lvalue.
1413                     fixups[0] = Fixups.add(fixups[0], null, out.size(),
1414                                            Fixups.U2_FORMAT, globalRef);
1415                     localRef = 0; // placeholder for fixups
1416                 } else {
1417                     localRef = 0; // fixed null value
1418                 }
1419                 unparseInt(e, localRef, out);
1420                 break;
1421             default: assert(false); continue;
1422             }
1423         }
1424     }
1425 
1426     static private
1427     void unparseInt(Layout.Element e, int value, ByteArrayOutputStream out) {
1428         int loBits = e.len * 8;
1429         if (loBits == 0) {
1430             // It is not stored at all ('V' layout).
1431             return;
1432         }
1433         if (loBits < 32) {
1434             int hiBits = 32 - loBits;
1435             int codedValue;
1436             if (e.flagTest(EF_SIGN))
1437                 codedValue = (value << hiBits) >> hiBits;
1438             else
1439                 codedValue = (value << hiBits) >>> hiBits;
1440             if (codedValue != value)
1441                 throw new InternalError("cannot code in "+e.len+" bytes: "+value);
1442         }
1443         // Write in big-endian order:
1444         for (int bitPos = loBits; (bitPos -= 8) >= 0; ) {
1445             out.write((byte)(value >>> bitPos));
1446         }
1447     }
1448 
1449 /*
1450     /// Testing.
1451     public static void main(String av[]) {
1452         int maxVal = 12;
1453         int iters = 0;
1454         boolean verbose;
1455         int ap = 0;
1456         while (ap < av.length) {
1457             if (!av[ap].startsWith("-"))  break;
1458             if (av[ap].startsWith("-m"))
1459                 maxVal = Integer.parseInt(av[ap].substring(2));
1460             else if (av[ap].startsWith("-i"))
1461                 iters = Integer.parseInt(av[ap].substring(2));
1462             else
1463                 throw new RuntimeException("Bad option: "+av[ap]);
1464             ap++;
1465         }
1466         verbose = (iters == 0);
1467         if (iters <= 0)  iters = 1;
1468         if (ap == av.length) {
1469             av = new String[] {
1470                 "HH",         // ClassFile.version
1471                 "RUH",        // SourceFile
1472                 "RCHRDNH",    // EnclosingMethod
1473                 "KQH",        // ConstantValue
1474                 "NH[RCH]",    // Exceptions
1475                 "NH[PHH]",    // LineNumberTable
1476                 "NH[PHOHRUHRSHH]",      // LocalVariableTable
1477                 "NH[PHPOHIIH]",         // CharacterRangeTable
1478                 "NH[PHHII]",            // CoverageTable
1479                 "NH[RCHRCNHRUNHFH]",    // InnerClasses
1480                 "NH[RMHNH[KLH]]",       // BootstrapMethods
1481                 "HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]", // Code
1482                 "=AnnotationDefault",
1483                 // Like metadata, but with a compact tag set:
1484                 "[NH[(1)]]"
1485                 +"[NH[(1)]]"
1486                 +"[RSHNH[RUH(1)]]"
1487                 +"[TB(0,1,3)[KIH](2)[KDH](5)[KFH](4)[KJH](7)[RSH](8)[RSHRUH](9)[RUH](10)[(-1)](6)[NH[(0)]]()[]]",
1488                 ""
1489             };
1490             ap = 0;
1491         }
1492         Utils.currentInstance.set(new PackerImpl());
1493         final int[][] counts = new int[2][3];  // int bci ref
1494         final Entry[] cpMap = new Entry[maxVal+1];
1495         for (int i = 0; i < cpMap.length; i++) {
1496             if (i == 0)  continue;  // 0 => null
1497             cpMap[i] = ConstantPool.getLiteralEntry(new Integer(i));
1498         }
1499         Package.Class cls = new Package().new Class("");
1500         cls.cpMap = cpMap;
1501         class TestValueStream extends ValueStream {
1502             java.util.Random rand = new java.util.Random(0);
1503             ArrayList history = new ArrayList();
1504             int ckidx = 0;
1505             int maxVal;
1506             boolean verbose;
1507             void reset() { history.clear(); ckidx = 0; }
1508             public int getInt(int bandIndex) {
1509                 counts[0][0]++;
1510                 int value = rand.nextInt(maxVal+1);
1511                 history.add(new Integer(bandIndex));
1512                 history.add(new Integer(value));
1513                 return value;
1514             }
1515             public void putInt(int bandIndex, int token) {
1516                 counts[1][0]++;
1517                 if (verbose)
1518                     System.out.print(" "+bandIndex+":"+token);
1519                 // Make sure this put parallels a previous get:
1520                 int check0 = ((Integer)history.get(ckidx+0)).intValue();
1521                 int check1 = ((Integer)history.get(ckidx+1)).intValue();
1522                 if (check0 != bandIndex || check1 != token) {
1523                     if (!verbose)
1524                         System.out.println(history.subList(0, ckidx));
1525                     System.out.println(" *** Should be "+check0+":"+check1);
1526                     throw new RuntimeException("Failed test!");
1527                 }
1528                 ckidx += 2;
1529             }
1530             public Entry getRef(int bandIndex) {
1531                 counts[0][2]++;
1532                 int value = getInt(bandIndex);
1533                 if (value < 0 || value > maxVal) {
1534                     System.out.println(" *** Unexpected ref code "+value);
1535                     return ConstantPool.getLiteralEntry(new Integer(value));
1536                 }
1537                 return cpMap[value];
1538             }
1539             public void putRef(int bandIndex, Entry ref) {
1540                 counts[1][2]++;
1541                 if (ref == null) {
1542                     putInt(bandIndex, 0);
1543                     return;
1544                 }
1545                 Number refValue = null;
1546                 if (ref instanceof ConstantPool.NumberEntry)
1547                     refValue = ((ConstantPool.NumberEntry)ref).numberValue();
1548                 int value;
1549                 if (!(refValue instanceof Integer)) {
1550                     System.out.println(" *** Unexpected ref "+ref);
1551                     value = -1;
1552                 } else {
1553                     value = ((Integer)refValue).intValue();
1554                 }
1555                 putInt(bandIndex, value);
1556             }
1557             public int encodeBCI(int bci) {
1558                 counts[1][1]++;
1559                 // move LSB to MSB of low byte
1560                 int code = (bci >> 8) << 8;  // keep high bits
1561                 code += (bci & 0xFE) >> 1;
1562                 code += (bci & 0x01) << 7;
1563                 return code ^ (8<<8);  // mark it clearly as coded
1564             }
1565             public int decodeBCI(int bciCode) {
1566                 counts[0][1]++;
1567                 bciCode ^= (8<<8);  // remove extra mark
1568                 int bci = (bciCode >> 8) << 8;  // keep high bits
1569                 bci += (bciCode & 0x7F) << 1;
1570                 bci += (bciCode & 0x80) >> 7;
1571                 return bci;
1572             }
1573         }
1574         TestValueStream tts = new TestValueStream();
1575         tts.maxVal = maxVal;
1576         tts.verbose = verbose;
1577         ByteArrayOutputStream buf = new ByteArrayOutputStream();
1578         for (int i = 0; i < (1 << 30); i = (i + 1) * 5) {
1579             int ei = tts.encodeBCI(i);
1580             int di = tts.decodeBCI(ei);
1581             if (di != i)  System.out.println("i="+Integer.toHexString(i)+
1582                                              " ei="+Integer.toHexString(ei)+
1583                                              " di="+Integer.toHexString(di));
1584         }
1585         while (iters-- > 0) {
1586             for (int i = ap; i < av.length; i++) {
1587                 String layout = av[i];
1588                 if (layout.startsWith("=")) {
1589                     String name = layout.substring(1);
1590                     for (Attribute a : standardDefs.values()) {
1591                         if (a.name().equals(name)) {
1592                             layout = a.layout().layout();
1593                             break;
1594                         }
1595                     }
1596                     if (layout.startsWith("=")) {
1597                         System.out.println("Could not find "+name+" in "+standardDefs.values());
1598                     }
1599                 }
1600                 Layout self = new Layout(0, "Foo", layout);
1601                 if (verbose) {
1602                     System.out.print("/"+layout+"/ => ");
1603                     System.out.println(Arrays.asList(self.elems));
1604                 }
1605                 buf.reset();
1606                 tts.reset();
1607                 Object fixups = self.unparse(tts, buf);
1608                 byte[] bytes = buf.toByteArray();
1609                 // Attach the references to the byte array.
1610                 Fixups.setBytes(fixups, bytes);
1611                 // Patch the references to their frozen values.
1612                 Fixups.finishRefs(fixups, bytes, new Index("test", cpMap));
1613                 if (verbose) {
1614                     System.out.print("  bytes: {");
1615                     for (int j = 0; j < bytes.length; j++) {
1616                         System.out.print(" "+bytes[j]);
1617                     }
1618                     System.out.println("}");
1619                 }
1620                 if (verbose) {
1621                     System.out.print("  parse: {");
1622                 }
1623                 self.parse(cls, bytes, 0, bytes.length, tts);
1624                 if (verbose) {
1625                     System.out.println("}");
1626                 }
1627             }
1628         }
1629         for (int j = 0; j <= 1; j++) {
1630             System.out.print("values "+(j==0?"read":"written")+": {");
1631             for (int k = 0; k < counts[j].length; k++) {
1632                 System.out.print(" "+counts[j][k]);
1633             }
1634             System.out.println(" }");
1635         }
1636     }
1637 //*/
1638 }