2667N/A * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 2362N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 2362N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2362N/A * or visit www.oracle.com if you need additional information or have any 0N/A * Represents an attribute in a class-file. 0N/A * Takes care to remember where constant pool indexes occur. 0N/A * Implements the "little language" of Pack200 for describing 0N/A * attribute layouts. 0N/A // Attribute instance fields. 0N/A // Canonicalized lists of trivial attrs (Deprecated, etc.) 0N/A // are used by trimToSize, in order to reduce footprint 0N/A // of some common cases. (Note that Code attributes are 0N/A // always zero size.) 0N/A // Find the canonical empty attribute with the given ctype, name, layout. 0N/A // Find canonical empty attribute with given ctype and name, 0N/A // and with the standard layout. 0N/A //define(sd, ATTR_CONTEXT_METHOD, "Code", "HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]"); 0N/A "(253)[(1)(2)(2)]" +
0N/A "(254)[(1)(2)(2)(2)]" +
0N/A "(255)[(1)NH[(2)]NH[(2)]]" +
0N/A "[TB(7)[RCH](8)[PH]()[]]"));
0N/A //define(sd, ATTR_CONTEXT_CODE, "CharacterRangeTable", "NH[PHPOHIIH]"); 0N/A //define(sd, ATTR_CONTEXT_CODE, "CoverageTable", "NH[PHHII]"); 0N/A // Note: Code and InnerClasses are special-cased elsewhere. 0N/A // Their layout specs. are given here for completeness. 0N/A // The Code spec is incomplete, in that it does not distinguish 0N/A // bytecode bytes or locate CP references. 0N/A // We define metadata using similar layouts 0N/A // for all five kinds of metadata attributes. 0N/A // Regular annotations are a counted list of [RSHNH[RUH(1)]][...] 0N/A // pack.method.attribute.RuntimeVisibleAnnotations=[NH[(1)]][RSHNH[RUH(1)]][TB...] 0N/A // Parameter annotations are a counted list of regular annotations. 0N/A // pack.method.attribute.RuntimeVisibleParameterAnnotations=[NH[(1)]][NH[(1)]][RSHNH[RUH(1)]][TB...] 0N/A // RuntimeInvisible annotations are defined similarly... 0N/A // Non-method annotations are defined similarly... 0N/A // Annotation are a simple tagged value [TB...] 0N/A // pack.attribute.method.AnnotationDefault=[TB...] 0N/A +
"\n # parameter_annotations :=" 0N/A +
"\n [ NB[(1)] ] # forward call to annotations" 0N/A +
"\n # annotations :=" 0N/A +
"\n [ NH[(1)] ] # forward call to annotation" 0N/A +
"\n # annotation :=" 0N/A +
"\n NH[RUH (1)] # forward call to value" 0N/A +
"\n [TB # Callable 2 encodes one tagged value." 0N/A +
"\n (\\B,\\C,\\I,\\S,\\Z)[KIH]" 0N/A +
"\n (\\e)[RSH RUH]" 0N/A +
"\n (\\[)[NH[(0)]] # backward self-call to value" 0N/A +
"\n (\\@)[RSH NH[RUH (0)]] # backward self-call to value" 0N/A /** Base class for any attributed object (Class, Field, Method, Code). 0N/A * Flags are included because they are used to help transmit the 0N/A * presence of attributes. That is, flags are a mix of modifier 0N/A * bits and attribute indicators. 0N/A public static abstract 0N/A // We need this abstract method to interpret embedded CP refs. 0N/A protected int flags;
// defined here for convenience 0N/A // Replace private writable attribute list 0N/A // with only trivial entries by public unique 0N/A // immutable attribute list with the same entries. 0N/A // Lightweight interface to hide details of band structure. 0N/A // Also used for testing. 0N/A public static abstract 0N/A static final byte EK_INT =
1;
// B H I SH etc. 0N/A static final byte EK_REF =
6;
// RUH, RUNH, KQH, etc. 0N/A static final byte EK_UN =
7;
// TB(...)[...] etc. 0N/A static final byte EK_CBLE =
10;
// [...][...] etc. 0N/A static final byte EF_SIGN =
1<<
0;
// INT is signed 0N/A static final byte EF_BACK =
1<<
3;
// call, callable, case is backward 0N/A /** A "class" of attributes, characterized by a context-type, name 0N/A * and format. The formats are specified in a "little language". 0N/A int ctype;
// attribute context type, e.g., ATTR_CONTEXT_CODE 0N/A boolean hasRefs;
// this kind of attr contains CP refs? 0N/A // Make the callables now, so they can be linked immediately. 0N/A // Next fill them in. 0N/A //System.out.println(Arrays.asList(elems)); 0N/A // simplest way to catch syntax errors... 0N/A // Some uses do not make a fresh one for each occurrence. 0N/A // For example, if layout == "", we only need one attr to share. 0N/A if (r !=
0)
return r;
0N/A if (r !=
0)
return r;
0N/A // If -ea, print out more informative strings! 0N/A byte len;
// scalar length of element 0N/A // If -ea, print out more informative strings! 0N/A /** Return a sequence of tokens from the given attribute bytes. 0N/A * Sequence elements will be 1-1 correspondent with my layout tokens. 0N/A /** Given a sequence of tokens, return the attribute bytes. 0N/A * Sequence elements must be 1-1 correspondent with my layout tokens. 0N/A * The returned object is a cookie for Fixups.finishRefs, which 0N/A * must be used to harden any references into integer indexes. 0N/A return fixups[
0];
// return ref-bearing cookie, if any 0N/A // Disallow layout syntax in the oldest protocol version. 0N/A // else the name is owned by the layout, and is processed elsewhere 0N/A // References (to a local cpMap) are embedded in the bytes. 0N/A /** Remove any informal "pretty printing" from the layout string. 0N/A * Removes blanks and control chars. 0N/A * Removes '#' comments (to end of line). 0N/A * Replaces '\c' by the decimal code of the character c. 0N/A * Replaces '0xNNN' by the decimal code of the hex number NNN. 0N/A // Skip whitespace and control chars 0N/A // Skip to end of line. 0N/A // Map a character reference to its decimal code. 0N/A // Map a hex numeral to its decimal code. 0N/A /// Subroutines for parsing and unparsing: 0N/A /** Parse the attribute layout language. 0N/A ( layout_element )* | ( callable )+ 0N/A ( integral | replication | union | call | reference ) 0N/A ( unsigned_int | signed_int | bc_index | bc_offset | flag ) 0N/A ( unsigned_int | signed_int ) 0N/A ( 'P' uint_type | 'PO' uint_type ) 0N/A ( 'B' | 'H' | 'I' | 'V' ) 0N/A 'N' uint_type '[' body ']' 0N/A 'T' any_int (union_case)* '(' ')' '[' (body)? ']' 0N/A '(' union_case_tag (',' union_case_tag)* ')' '[' (body)? ']' 0N/A ( numeral | numeral '-' numeral ) 0N/A reference_type ( 'N' )? uint_type 0N/A ( constant_ref | schema_ref | utf8_ref | untyped_ref ) 0N/A ( 'KI' | 'KJ' | 'KF' | 'KD' | 'KS' | 'KQ' ) 0N/A ( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' ) 0N/A '(' ('-')? (digit)+ ')' 0N/A ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ) 0N/A //System.out.println("at "+i+": ..."+layout.substring(i)); 0N/A /// layout_element: integral 0N/A case 'B':
case 'H':
case 'I':
case 'V':
// unsigned_int 0N/A case 'S':
// signed_int 0N/A case 'P':
// bc_index 0N/A // bc_index: 'PO' tokenizeUInt 0N/A // must follow P or PO: 0N/A { i = -i;
continue; }
// fail 0N/A i++;
// move forward 0N/A case 'O':
// bc_offset 0N/A // must follow P or PO: 0N/A { i = -i;
continue; }
// fail 0N/A case 'N':
// replication: 'N' uint '[' elem ... ']' 0N/A { i = -i;
continue; }
// fail 0N/A case 'T':
// union: 'T' any_int union_case* '(' ')' '[' body ']' 0N/A // Keep parsing cases until we hit the default case. 0N/A { i = -i;
break; }
// fail 0N/A { i = -i;
break; }
// fail 0N/A // Check for duplication. 0N/A body = i;
// missing body, which is legal here 0N/A break;
// done with the whole union 0N/A // Parse a case string. 0N/A // Look for multiple case tags: 0N/A // Check for a case range (new in 1.6). 0N/A { i = -i;
break; }
// fail 0N/A // Add a case for each value in value0..value1 0N/A // "backward case" repeats a body 0N/A break;
// done with this case 0N/A { i = -i;
break; }
// fail 0N/A case '(':
// call: '(' '-'? digit+ ')' 0N/A { i = -i;
continue; }
// fail 0N/A // Is it a (recursive) backward call? 0N/A // Yes. Mark both caller and callee backward. 0N/A case 'K':
// reference_type: constant_ref 0N/A default: { i = -i;
continue; }
// fail 0N/A case 'R':
// schema_ref 0N/A default: { i = -i;
continue; }
// fail 0N/A default: { i = -i;
continue; }
// fail 0N/A // further parsing of refs 0N/A // reference: reference_type -><- ( 'N' )? tokenizeUInt 0N/A i++;
// move forward 0N/A // store the new element 0N/A // Parse several independent layout bodies: "[foo][bar]...[baz]" 0N/A // No empty bodies, please. 0N/A // skip balanced [...[...]...] 0N/A --i;
// get before bracket 0N/A return i;
// return closing bracket 0N/A return c >=
'0' && c <=
'9';
0N/A /** Find an occurrence of hyphen '-' between two numerals. */ 0N/A // matched /[0-9]--?[0-9]/; return position of dash 0N/A // skip backward over a sign 0N/A /** For compatibility with 1.5 pack, expand 1-5 into 1,2,3,4,5. */ 0N/A int sofar =
0;
// how far have we processed the layout? 0N/A // for each dash, collect everything up to the dash 0N/A // then collect intermediate values 0N/A // Parse attribute bytes, putting values into bands. Returns new pos. 0N/A // Used when reading a class file (local refs resolved with local cpMap). 0N/A // Also used for ad hoc scanning. 0N/A int[]
buf = {
0 };
// for calls to parseInt, holds 2nd result 0N/A // PH: transmit R(bci), store bci 0N/A // POH: transmit D(R(bci)), store bci 0N/A // OH: transmit D(R(bci)), store D(bci) 0N/A break;
// already transmitted the scalar value 0N/A break;
// already transmitted the scalar value 0N/A // Adjust band offset if it is a backward call. 0N/A break;
// no additional scalar value to transmit 0N/A // Cf. ClassReader.readSignatureRef. 0N/A default:
assert(
false);
continue;
0N/A // Read in big-endian order: 0N/A // sign-extend subword value 0N/A // Format attribute bytes, drawing values from bands. 0N/A // Used when emptying attribute bands into a package model. 0N/A // (At that point CP refs. are not yet assigned indexes.) 0N/A int BCI,
RBCI;
// "RBCI" is R(BCI), BCI's coded representation 0N/A // PH: transmit R(bci), store bci 0N/A // POH: transmit D(R(bci)), store bci 0N/A // OH: transmit D(R(bci)), store D(bci) 0N/A // It's a one-element array, really an lvalue. 0N/A default:
assert(
false);
continue;
0N/A // It is not stored at all ('V' layout). 0N/A // Write in big-endian order: 0N/A public static void main(String av[]) { 0N/A while (ap < av.length) { 0N/A if (!av[ap].startsWith("-")) break; 0N/A if (av[ap].startsWith("-m")) 0N/A maxVal = Integer.parseInt(av[ap].substring(2)); 0N/A else if (av[ap].startsWith("-i")) 0N/A iters = Integer.parseInt(av[ap].substring(2)); 0N/A throw new RuntimeException("Bad option: "+av[ap]); 0N/A verbose = (iters == 0); 0N/A if (iters <= 0) iters = 1; 0N/A if (ap == av.length) { 0N/A "HH", // ClassFile.version 0N/A "RUH", // SourceFile 0N/A "RCHRDNH", // EnclosingMethod 0N/A "KQH", // ConstantValue 0N/A "NH[RCH]", // Exceptions 0N/A "NH[PHH]", // LineNumberTable 0N/A "NH[PHOHRUHRSHH]", // LocalVariableTable 0N/A "NH[PHPOHIIH]", // CharacterRangeTable 0N/A "NH[PHHII]", // CoverageTable 0N/A "NH[RCHRCNHRUNHFH]", // InnerClasses 0N/A "HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]", // Code 0N/A "=AnnotationDefault", 0N/A // Like metadata, but with a compact tag set: 0N/A +"[TB(0,1,3)[KIH](2)[KDH](5)[KFH](4)[KJH](7)[RSH](8)[RSHRUH](9)[RUH](10)[(2)](6)[NH[(3)]]()[]]", 0N/A final int[][] counts = new int[2][3]; // int bci ref 0N/A final Entry[] cpMap = new Entry[maxVal+1]; 0N/A for (int i = 0; i < cpMap.length; i++) { 0N/A if (i == 0) continue; // 0 => null 0N/A cpMap[i] = ConstantPool.getLiteralEntry(new Integer(i)); 0N/A Class cls = new Package().new Class(""); 0N/A class TestValueStream extends ValueStream { 0N/A Random rand = new Random(0); 0N/A ArrayList history = new ArrayList(); 0N/A void reset() { history.clear(); ckidx = 0; } 0N/A public int getInt(int bandIndex) { 0N/A int value = rand.nextInt(maxVal+1); 0N/A history.add(new Integer(bandIndex)); 0N/A history.add(new Integer(value)); 0N/A public void putInt(int bandIndex, int token) { 0N/A System.out.print(" "+bandIndex+":"+token); 0N/A // Make sure this put parallels a previous get: 0N/A int check0 = ((Integer)history.get(ckidx+0)).intValue(); 0N/A int check1 = ((Integer)history.get(ckidx+1)).intValue(); 0N/A if (check0 != bandIndex || check1 != token) { 0N/A System.out.println(history.subList(0, ckidx)); 0N/A System.out.println(" *** Should be "+check0+":"+check1); 0N/A throw new RuntimeException("Failed test!"); 0N/A public Entry getRef(int bandIndex) { 0N/A int value = getInt(bandIndex); 0N/A if (value < 0 || value > maxVal) { 0N/A System.out.println(" *** Unexpected ref code "+value); 0N/A return ConstantPool.getLiteralEntry(new Integer(value)); 0N/A return cpMap[value]; 0N/A public void putRef(int bandIndex, Entry ref) { 0N/A putInt(bandIndex, 0); 0N/A Number refValue = null; 0N/A if (ref instanceof ConstantPool.NumberEntry) 0N/A refValue = ((ConstantPool.NumberEntry)ref).numberValue(); 0N/A if (!(refValue instanceof Integer)) { 0N/A System.out.println(" *** Unexpected ref "+ref); 0N/A value = ((Integer)refValue).intValue(); 0N/A putInt(bandIndex, value); 0N/A public int encodeBCI(int bci) { 0N/A // move LSB to MSB of low byte 0N/A int code = (bci >> 8) << 8; // keep high bits 0N/A code += (bci & 0xFE) >> 1; 0N/A code += (bci & 0x01) << 7; 0N/A return code ^ (8<<8); // mark it clearly as coded 0N/A public int decodeBCI(int bciCode) { 0N/A bciCode ^= (8<<8); // remove extra mark 0N/A int bci = (bciCode >> 8) << 8; // keep high bits 0N/A bci += (bciCode & 0x7F) << 1; 0N/A bci += (bciCode & 0x80) >> 7; 0N/A TestValueStream tts = new TestValueStream(); 0N/A tts.maxVal = maxVal; 0N/A tts.verbose = verbose; 0N/A ByteArrayOutputStream buf = new ByteArrayOutputStream(); 0N/A for (int i = 0; i < (1 << 30); i = (i + 1) * 5) { 0N/A int ei = tts.encodeBCI(i); 0N/A int di = tts.decodeBCI(ei); 0N/A if (di != i) System.out.println("i="+Integer.toHexString(i)+ 0N/A " ei="+Integer.toHexString(ei)+ 0N/A " di="+Integer.toHexString(di)); 0N/A while (iters-- > 0) { 0N/A for (int i = ap; i < av.length; i++) { 0N/A String layout = av[i]; 0N/A if (layout.startsWith("=")) { 0N/A String name = layout.substring(1); 0N/A for (Iterator j = standardDefs.values().iterator(); j.hasNext(); ) { 0N/A Attribute a = (Attribute) j.next(); 0N/A if (a.name().equals(name)) { 0N/A layout = a.layout().layout(); 0N/A if (layout.startsWith("=")) { 0N/A System.out.println("Could not find "+name+" in "+standardDefs.values()); 0N/A Layout self = new Layout(0, "Foo", layout); 0N/A System.out.print("/"+layout+"/ => "); 0N/A System.out.println(Arrays.asList(self.elems)); 0N/A Object fixups = self.unparse(tts, buf); 0N/A byte[] bytes = buf.toByteArray(); 0N/A // Attach the references to the byte array. 0N/A Fixups.setBytes(fixups, bytes); 0N/A // Patch the references to their frozen values. 0N/A Fixups.finishRefs(fixups, bytes, new Index("test", cpMap)); 0N/A System.out.print(" bytes: {"); 0N/A for (int j = 0; j < bytes.length; j++) { 0N/A System.out.print(" "+bytes[j]); 0N/A System.out.println("}"); 0N/A System.out.print(" parse: {"); 0N/A self.parse(0, cls, bytes, 0, bytes.length, tts); 0N/A System.out.println("}"); 0N/A for (int j = 0; j <= 1; j++) { 0N/A System.out.print("values "+(j==0?"read":"written")+": {"); 0N/A for (int k = 0; k < counts[j].length; k++) { 0N/A System.out.print(" "+counts[j][k]); 0N/A System.out.println(" }");