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