Categories:
Audio (13)
Biotech (29)
Bytecode (36)
Database (77)
Framework (7)
Game (7)
General (507)
Graphics (53)
I/O (35)
IDE (2)
JAR Tools (101)
JavaBeans (21)
JDBC (121)
JDK (426)
JSP (20)
Logging (108)
Mail (58)
Messaging (8)
Network (84)
PDF (97)
Report (7)
Scripting (84)
Security (32)
Server (121)
Servlet (26)
SOAP (24)
Testing (54)
Web (15)
XML (309)
Collections:
Other Resources:
JDK 11 java.base.jmod - Base Module
JDK 11 java.base.jmod is the JMOD file for JDK 11 Base module.
JDK 11 Base module compiled class files are stored in \fyicenter\jdk-11.0.1\jmods\java.base.jmod.
JDK 11 Base module compiled class files are also linked and stored in the \fyicenter\jdk-11.0.1\lib\modules JImage file.
JDK 11 Base module source code files are stored in \fyicenter\jdk-11.0.1\lib\src.zip\java.base.
You can click and view the content of each source code file in the list below.
✍: FYIcenter
⏎ com/sun/java/util/jar/pack/PackageReader.java
/* * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package com.sun.java.util.jar.pack; import com.sun.java.util.jar.pack.ConstantPool.*; import com.sun.java.util.jar.pack.Package.Class; import com.sun.java.util.jar.pack.Package.File; import com.sun.java.util.jar.pack.Package.InnerClass; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.PrintStream; import java.io.FilterInputStream; import java.io.BufferedInputStream; import java.io.InputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Map; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Set; import static com.sun.java.util.jar.pack.Constants.*; /** * Reader for a package file. * * @see PackageWriter * @author John Rose */ class PackageReader extends BandStructure { Package pkg; byte[] bytes; LimitedBuffer in; Package.Version packageVersion; PackageReader(Package pkg, InputStream in) throws IOException { this.pkg = pkg; this.in = new LimitedBuffer(in); } /** A buffered input stream which is careful not to * read its underlying stream ahead of a given mark, * called the 'readLimit'. This property declares * the maximum number of characters that future reads * can consume from the underlying stream. */ static class LimitedBuffer extends BufferedInputStream { long served; // total number of charburgers served int servedPos; // ...as of this value of super.pos long limit; // current declared limit long buffered; public boolean atLimit() { boolean z = (getBytesServed() == limit); assert(!z || limit == buffered); return z; } public long getBytesServed() { return served + (pos - servedPos); } public void setReadLimit(long newLimit) { if (newLimit == -1) limit = -1; else limit = getBytesServed() + newLimit; } public long getReadLimit() { if (limit == -1) return limit; else return limit - getBytesServed(); } public int read() throws IOException { if (pos < count) { // fast path return buf[pos++] & 0xFF; } served += (pos - servedPos); int ch = super.read(); servedPos = pos; if (ch >= 0) served += 1; assert(served <= limit || limit == -1); return ch; } public int read(byte b[], int off, int len) throws IOException { served += (pos - servedPos); int nr = super.read(b, off, len); servedPos = pos; if (nr >= 0) served += nr; //assert(served <= limit || limit == -1); return nr; } public long skip(long n) throws IOException { throw new RuntimeException("no skipping"); } LimitedBuffer(InputStream originalIn) { super(null, 1<<14); servedPos = pos; super.in = new FilterInputStream(originalIn) { public int read() throws IOException { if (buffered == limit) return -1; ++buffered; return super.read(); } public int read(byte b[], int off, int len) throws IOException { if (buffered == limit) return -1; if (limit != -1) { long remaining = limit - buffered; if (len > remaining) len = (int)remaining; } int nr = super.read(b, off, len); if (nr >= 0) buffered += nr; return nr; } }; } } void read() throws IOException { boolean ok = false; try { // pack200_archive: // file_header // *band_headers :BYTE1 // cp_bands // attr_definition_bands // ic_bands // class_bands // bc_bands // file_bands readFileHeader(); readBandHeaders(); readConstantPool(); // cp_bands readAttrDefs(); readInnerClasses(); Class[] classes = readClasses(); readByteCodes(); readFiles(); // file_bands assert(archiveSize1 == 0 || in.atLimit()); assert(archiveSize1 == 0 || in.getBytesServed() == archiveSize0+archiveSize1); all_bands.doneDisbursing(); // As a post-pass, build constant pools and inner classes. for (int i = 0; i < classes.length; i++) { reconstructClass(classes[i]); } ok = true; } catch (Exception ee) { Utils.log.warning("Error on input: "+ee, ee); if (verbose > 0) Utils.log.info("Stream offsets:"+ " served="+in.getBytesServed()+ " buffered="+in.buffered+ " limit="+in.limit); //if (verbose > 0) ee.printStackTrace(); if (ee instanceof IOException) throw (IOException)ee; if (ee instanceof RuntimeException) throw (RuntimeException)ee; throw new Error("error unpacking", ee); } } // Temporary count values, until band decoding gets rolling. int[] tagCount = new int[CONSTANT_Limit]; int numFiles; int numAttrDefs; int numInnerClasses; int numClasses; void readFileHeader() throws IOException { // file_header: // archive_magic archive_header readArchiveMagic(); readArchiveHeader(); } // Local routine used to parse fixed-format scalars // in the file_header: private int getMagicInt32() throws IOException { int res = 0; for (int i = 0; i < 4; i++) { res <<= 8; res |= (archive_magic.getByte() & 0xFF); } return res; } static final int MAGIC_BYTES = 4; void readArchiveMagic() throws IOException { // Read a minimum of bytes in the first gulp. in.setReadLimit(MAGIC_BYTES + AH_LENGTH_MIN); // archive_magic: // #archive_magic_word :BYTE1[4] archive_magic.expectLength(MAGIC_BYTES); archive_magic.readFrom(in); // read and check magic numbers: int magic = getMagicInt32(); if (pkg.magic != magic) { throw new IOException("Unexpected package magic number: got " + magic + "; expected " + pkg.magic); } archive_magic.doneDisbursing(); } // Fixed 6211177, converted to throw IOException void checkArchiveVersion() throws IOException { Package.Version versionFound = null; for (Package.Version v : new Package.Version[] { JAVA8_PACKAGE_VERSION, JAVA7_PACKAGE_VERSION, JAVA6_PACKAGE_VERSION, JAVA5_PACKAGE_VERSION }) { if (packageVersion.equals(v)) { versionFound = v; break; } } if (versionFound == null) { String expVer = JAVA8_PACKAGE_VERSION.toString() + "OR" + JAVA7_PACKAGE_VERSION.toString() + " OR " + JAVA6_PACKAGE_VERSION.toString() + " OR " + JAVA5_PACKAGE_VERSION.toString(); throw new IOException("Unexpected package minor version: got " + packageVersion.toString() + "; expected " + expVer); } } void readArchiveHeader() throws IOException { // archive_header: // #archive_minver :UNSIGNED5[1] // #archive_majver :UNSIGNED5[1] // #archive_options :UNSIGNED5[1] // (archive_file_counts) ** (#have_file_headers) // (archive_special_counts) ** (#have_special_formats) // cp_counts // class_counts // // archive_file_counts: // #archive_size_hi :UNSIGNED5[1] // #archive_size_lo :UNSIGNED5[1] // #archive_next_count :UNSIGNED5[1] // #archive_modtime :UNSIGNED5[1] // #file_count :UNSIGNED5[1] // // class_counts: // #ic_count :UNSIGNED5[1] // #default_class_minver :UNSIGNED5[1] // #default_class_majver :UNSIGNED5[1] // #class_count :UNSIGNED5[1] // // archive_special_counts: // #band_headers_size :UNSIGNED5[1] // #attr_definition_count :UNSIGNED5[1] // archive_header_0.expectLength(AH_LENGTH_0); archive_header_0.readFrom(in); int minver = archive_header_0.getInt(); int majver = archive_header_0.getInt(); packageVersion = Package.Version.of(majver, minver); checkArchiveVersion(); this.initHighestClassVersion(JAVA7_MAX_CLASS_VERSION); archiveOptions = archive_header_0.getInt(); archive_header_0.doneDisbursing(); // detect archive optional fields in archive header boolean haveSpecial = testBit(archiveOptions, AO_HAVE_SPECIAL_FORMATS); boolean haveFiles = testBit(archiveOptions, AO_HAVE_FILE_HEADERS); boolean haveNumbers = testBit(archiveOptions, AO_HAVE_CP_NUMBERS); boolean haveCPExtra = testBit(archiveOptions, AO_HAVE_CP_EXTRAS); initAttrIndexLimit(); // now we are ready to use the data: archive_header_S.expectLength(haveFiles? AH_LENGTH_S: 0); archive_header_S.readFrom(in); if (haveFiles) { long sizeHi = archive_header_S.getInt(); long sizeLo = archive_header_S.getInt(); archiveSize1 = (sizeHi << 32) + ((sizeLo << 32) >>> 32); // Set the limit, now, up to the file_bits. in.setReadLimit(archiveSize1); // for debug only } else { archiveSize1 = 0; in.setReadLimit(-1); // remove limitation } archive_header_S.doneDisbursing(); archiveSize0 = in.getBytesServed(); int remainingHeaders = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S; if (haveFiles) remainingHeaders += AH_FILE_HEADER_LEN; if (haveSpecial) remainingHeaders += AH_SPECIAL_FORMAT_LEN; if (haveNumbers) remainingHeaders += AH_CP_NUMBER_LEN; if (haveCPExtra) remainingHeaders += AH_CP_EXTRA_LEN; archive_header_1.expectLength(remainingHeaders); archive_header_1.readFrom(in); if (haveFiles) { archiveNextCount = archive_header_1.getInt(); pkg.default_modtime = archive_header_1.getInt(); numFiles = archive_header_1.getInt(); } else { archiveNextCount = 0; numFiles = 0; } if (haveSpecial) { band_headers.expectLength(archive_header_1.getInt()); numAttrDefs = archive_header_1.getInt(); } else { band_headers.expectLength(0); numAttrDefs = 0; } readConstantPoolCounts(haveNumbers, haveCPExtra); numInnerClasses = archive_header_1.getInt(); minver = (short) archive_header_1.getInt(); majver = (short) archive_header_1.getInt(); pkg.defaultClassVersion = Package.Version.of(majver, minver); numClasses = archive_header_1.getInt(); archive_header_1.doneDisbursing(); // set some derived archive bits if (testBit(archiveOptions, AO_DEFLATE_HINT)) { pkg.default_options |= FO_DEFLATE_HINT; } } void readBandHeaders() throws IOException { band_headers.readFrom(in); bandHeaderBytePos = 1; // Leave room to pushback the initial XB byte. bandHeaderBytes = new byte[bandHeaderBytePos + band_headers.length()]; for (int i = bandHeaderBytePos; i < bandHeaderBytes.length; i++) { bandHeaderBytes[i] = (byte) band_headers.getByte(); } band_headers.doneDisbursing(); } void readConstantPoolCounts(boolean haveNumbers, boolean haveCPExtra) throws IOException { // size the constant pools: for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { // cp_counts: // #cp_Utf8_count :UNSIGNED5[1] // (cp_number_counts) ** (#have_cp_numbers) // #cp_String_count :UNSIGNED5[1] // #cp_Class_count :UNSIGNED5[1] // #cp_Signature_count :UNSIGNED5[1] // #cp_Descr_count :UNSIGNED5[1] // #cp_Field_count :UNSIGNED5[1] // #cp_Method_count :UNSIGNED5[1] // #cp_Imethod_count :UNSIGNED5[1] // (cp_attr_counts) ** (#have_cp_attr_counts) // // cp_number_counts: // #cp_Int_count :UNSIGNED5[1] // #cp_Float_count :UNSIGNED5[1] // #cp_Long_count :UNSIGNED5[1] // #cp_Double_count :UNSIGNED5[1] // // cp_extra_counts: // #cp_MethodHandle_count :UNSIGNED5[1] // #cp_MethodType_count :UNSIGNED5[1] // #cp_InvokeDynamic_count :UNSIGNED5[1] // #cp_BootstrapMethod_count :UNSIGNED5[1] // byte tag = ConstantPool.TAGS_IN_ORDER[k]; if (!haveNumbers) { // These four counts are optional. switch (tag) { case CONSTANT_Integer: case CONSTANT_Float: case CONSTANT_Long: case CONSTANT_Double: continue; } } if (!haveCPExtra) { // These four counts are optional. switch (tag) { case CONSTANT_MethodHandle: case CONSTANT_MethodType: case CONSTANT_InvokeDynamic: case CONSTANT_BootstrapMethod: continue; } } tagCount[tag] = archive_header_1.getInt(); } } protected Index getCPIndex(byte tag) { return pkg.cp.getIndexByTag(tag); } Index initCPIndex(byte tag, Entry[] cpMap) { if (verbose > 3) { for (int i = 0; i < cpMap.length; i++) { Utils.log.fine("cp.add "+cpMap[i]); } } Index index = ConstantPool.makeIndex(ConstantPool.tagName(tag), cpMap); if (verbose > 1) Utils.log.fine("Read "+index); pkg.cp.initIndexByTag(tag, index); return index; } void checkLegacy(String bandname) { if (packageVersion.lessThan(JAVA7_PACKAGE_VERSION)) { throw new RuntimeException("unexpected band " + bandname); } } void readConstantPool() throws IOException { // cp_bands: // cp_Utf8 // *cp_Int :UDELTA5 // *cp_Float :UDELTA5 // cp_Long // cp_Double // *cp_String :UDELTA5 (cp_Utf8) // *cp_Class :UDELTA5 (cp_Utf8) // cp_Signature // cp_Descr // cp_Field // cp_Method // cp_Imethod if (verbose > 0) Utils.log.info("Reading CP"); for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { byte tag = ConstantPool.TAGS_IN_ORDER[k]; int len = tagCount[tag]; Entry[] cpMap = new Entry[len]; if (verbose > 0) Utils.log.info("Reading "+cpMap.length+" "+ConstantPool.tagName(tag)+" entries..."); switch (tag) { case CONSTANT_Utf8: readUtf8Bands(cpMap); break; case CONSTANT_Integer: cp_Int.expectLength(cpMap.length); cp_Int.readFrom(in); for (int i = 0; i < cpMap.length; i++) { int x = cp_Int.getInt(); // coding handles signs OK cpMap[i] = ConstantPool.getLiteralEntry(x); } cp_Int.doneDisbursing(); break; case CONSTANT_Float: cp_Float.expectLength(cpMap.length); cp_Float.readFrom(in); for (int i = 0; i < cpMap.length; i++) { int x = cp_Float.getInt(); float fx = Float.intBitsToFloat(x); cpMap[i] = ConstantPool.getLiteralEntry(fx); } cp_Float.doneDisbursing(); break; case CONSTANT_Long: // cp_Long: // *cp_Long_hi :UDELTA5 // *cp_Long_lo :DELTA5 cp_Long_hi.expectLength(cpMap.length); cp_Long_hi.readFrom(in); cp_Long_lo.expectLength(cpMap.length); cp_Long_lo.readFrom(in); for (int i = 0; i < cpMap.length; i++) { long hi = cp_Long_hi.getInt(); long lo = cp_Long_lo.getInt(); long x = (hi << 32) + ((lo << 32) >>> 32); cpMap[i] = ConstantPool.getLiteralEntry(x); } cp_Long_hi.doneDisbursing(); cp_Long_lo.doneDisbursing(); break; case CONSTANT_Double: // cp_Double: // *cp_Double_hi :UDELTA5 // *cp_Double_lo :DELTA5 cp_Double_hi.expectLength(cpMap.length); cp_Double_hi.readFrom(in); cp_Double_lo.expectLength(cpMap.length); cp_Double_lo.readFrom(in); for (int i = 0; i < cpMap.length; i++) { long hi = cp_Double_hi.getInt(); long lo = cp_Double_lo.getInt(); long x = (hi << 32) + ((lo << 32) >>> 32); double dx = Double.longBitsToDouble(x); cpMap[i] = ConstantPool.getLiteralEntry(dx); } cp_Double_hi.doneDisbursing(); cp_Double_lo.doneDisbursing(); break; case CONSTANT_String: cp_String.expectLength(cpMap.length); cp_String.readFrom(in); cp_String.setIndex(getCPIndex(CONSTANT_Utf8)); for (int i = 0; i < cpMap.length; i++) { cpMap[i] = ConstantPool.getLiteralEntry(cp_String.getRef().stringValue()); } cp_String.doneDisbursing(); break; case CONSTANT_Class: cp_Class.expectLength(cpMap.length); cp_Class.readFrom(in); cp_Class.setIndex(getCPIndex(CONSTANT_Utf8)); for (int i = 0; i < cpMap.length; i++) { cpMap[i] = ConstantPool.getClassEntry(cp_Class.getRef().stringValue()); } cp_Class.doneDisbursing(); break; case CONSTANT_Signature: readSignatureBands(cpMap); break; case CONSTANT_NameandType: // cp_Descr: // *cp_Descr_type :DELTA5 (cp_Signature) // *cp_Descr_name :UDELTA5 (cp_Utf8) cp_Descr_name.expectLength(cpMap.length); cp_Descr_name.readFrom(in); cp_Descr_name.setIndex(getCPIndex(CONSTANT_Utf8)); cp_Descr_type.expectLength(cpMap.length); cp_Descr_type.readFrom(in); cp_Descr_type.setIndex(getCPIndex(CONSTANT_Signature)); for (int i = 0; i < cpMap.length; i++) { Entry ref = cp_Descr_name.getRef(); Entry ref2 = cp_Descr_type.getRef(); cpMap[i] = ConstantPool.getDescriptorEntry((Utf8Entry)ref, (SignatureEntry)ref2); } cp_Descr_name.doneDisbursing(); cp_Descr_type.doneDisbursing(); break; case CONSTANT_Fieldref: readMemberRefs(tag, cpMap, cp_Field_class, cp_Field_desc); break; case CONSTANT_Methodref: readMemberRefs(tag, cpMap, cp_Method_class, cp_Method_desc); break; case CONSTANT_InterfaceMethodref: readMemberRefs(tag, cpMap, cp_Imethod_class, cp_Imethod_desc); break; case CONSTANT_MethodHandle: if (cpMap.length > 0) { checkLegacy(cp_MethodHandle_refkind.name()); } cp_MethodHandle_refkind.expectLength(cpMap.length); cp_MethodHandle_refkind.readFrom(in); cp_MethodHandle_member.expectLength(cpMap.length); cp_MethodHandle_member.readFrom(in); cp_MethodHandle_member.setIndex(getCPIndex(CONSTANT_AnyMember)); for (int i = 0; i < cpMap.length; i++) { byte refKind = (byte) cp_MethodHandle_refkind.getInt(); MemberEntry memRef = (MemberEntry) cp_MethodHandle_member.getRef(); cpMap[i] = ConstantPool.getMethodHandleEntry(refKind, memRef); } cp_MethodHandle_refkind.doneDisbursing(); cp_MethodHandle_member.doneDisbursing(); break; case CONSTANT_MethodType: if (cpMap.length > 0) { checkLegacy(cp_MethodType.name()); } cp_MethodType.expectLength(cpMap.length); cp_MethodType.readFrom(in); cp_MethodType.setIndex(getCPIndex(CONSTANT_Signature)); for (int i = 0; i < cpMap.length; i++) { SignatureEntry typeRef = (SignatureEntry) cp_MethodType.getRef(); cpMap[i] = ConstantPool.getMethodTypeEntry(typeRef); } cp_MethodType.doneDisbursing(); break; case CONSTANT_InvokeDynamic: if (cpMap.length > 0) { checkLegacy(cp_InvokeDynamic_spec.name()); } cp_InvokeDynamic_spec.expectLength(cpMap.length); cp_InvokeDynamic_spec.readFrom(in); cp_InvokeDynamic_spec.setIndex(getCPIndex(CONSTANT_BootstrapMethod)); cp_InvokeDynamic_desc.expectLength(cpMap.length); cp_InvokeDynamic_desc.readFrom(in); cp_InvokeDynamic_desc.setIndex(getCPIndex(CONSTANT_NameandType)); for (int i = 0; i < cpMap.length; i++) { BootstrapMethodEntry bss = (BootstrapMethodEntry) cp_InvokeDynamic_spec.getRef(); DescriptorEntry descr = (DescriptorEntry) cp_InvokeDynamic_desc.getRef(); cpMap[i] = ConstantPool.getInvokeDynamicEntry(bss, descr); } cp_InvokeDynamic_spec.doneDisbursing(); cp_InvokeDynamic_desc.doneDisbursing(); break; case CONSTANT_BootstrapMethod: if (cpMap.length > 0) { checkLegacy(cp_BootstrapMethod_ref.name()); } cp_BootstrapMethod_ref.expectLength(cpMap.length); cp_BootstrapMethod_ref.readFrom(in); cp_BootstrapMethod_ref.setIndex(getCPIndex(CONSTANT_MethodHandle)); cp_BootstrapMethod_arg_count.expectLength(cpMap.length); cp_BootstrapMethod_arg_count.readFrom(in); int totalArgCount = cp_BootstrapMethod_arg_count.getIntTotal(); cp_BootstrapMethod_arg.expectLength(totalArgCount); cp_BootstrapMethod_arg.readFrom(in); cp_BootstrapMethod_arg.setIndex(getCPIndex(CONSTANT_LoadableValue)); for (int i = 0; i < cpMap.length; i++) { MethodHandleEntry bsm = (MethodHandleEntry) cp_BootstrapMethod_ref.getRef(); int argc = cp_BootstrapMethod_arg_count.getInt(); Entry[] argRefs = new Entry[argc]; for (int j = 0; j < argc; j++) { argRefs[j] = cp_BootstrapMethod_arg.getRef(); } cpMap[i] = ConstantPool.getBootstrapMethodEntry(bsm, argRefs); } cp_BootstrapMethod_ref.doneDisbursing(); cp_BootstrapMethod_arg_count.doneDisbursing(); cp_BootstrapMethod_arg.doneDisbursing(); break; default: throw new AssertionError("unexpected CP tag in package"); } Index index = initCPIndex(tag, cpMap); if (optDumpBands) { try (PrintStream ps = new PrintStream(getDumpStream(index, ".idx"))) { printArrayTo(ps, index.cpMap, 0, index.cpMap.length); } } } cp_bands.doneDisbursing(); if (optDumpBands || verbose > 1) { for (byte tag = CONSTANT_GroupFirst; tag < CONSTANT_GroupLimit; tag++) { Index index = pkg.cp.getIndexByTag(tag); if (index == null || index.isEmpty()) continue; Entry[] cpMap = index.cpMap; if (verbose > 1) Utils.log.info("Index group "+ConstantPool.tagName(tag)+" contains "+cpMap.length+" entries."); if (optDumpBands) { try (PrintStream ps = new PrintStream(getDumpStream(index.debugName, tag, ".gidx", index))) { printArrayTo(ps, cpMap, 0, cpMap.length, true); } } } } setBandIndexes(); } void readUtf8Bands(Entry[] cpMap) throws IOException { // cp_Utf8: // *cp_Utf8_prefix :DELTA5 // *cp_Utf8_suffix :UNSIGNED5 // *cp_Utf8_chars :CHAR3 // *cp_Utf8_big_suffix :DELTA5 // (*cp_Utf8_big_chars :DELTA5) // ** length(cp_Utf8_big_suffix) int len = cpMap.length; if (len == 0) return; // nothing to read // Bands have implicit leading zeroes, for the empty string: final int SUFFIX_SKIP_1 = 1; final int PREFIX_SKIP_2 = 2; // First band: Read lengths of shared prefixes. cp_Utf8_prefix.expectLength(Math.max(0, len - PREFIX_SKIP_2)); cp_Utf8_prefix.readFrom(in); // Second band: Read lengths of unshared suffixes: cp_Utf8_suffix.expectLength(Math.max(0, len - SUFFIX_SKIP_1)); cp_Utf8_suffix.readFrom(in); char[][] suffixChars = new char[len][]; int bigSuffixCount = 0; // Third band: Read the char values in the unshared suffixes: cp_Utf8_chars.expectLength(cp_Utf8_suffix.getIntTotal()); cp_Utf8_chars.readFrom(in); for (int i = 0; i < len; i++) { int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt(); if (suffix == 0 && i >= SUFFIX_SKIP_1) { // chars are packed in cp_Utf8_big_chars bigSuffixCount += 1; continue; } suffixChars[i] = new char[suffix]; for (int j = 0; j < suffix; j++) { int ch = cp_Utf8_chars.getInt(); assert(ch == (char)ch); suffixChars[i][j] = (char)ch; } } cp_Utf8_chars.doneDisbursing(); // Fourth band: Go back and size the specially packed strings. int maxChars = 0; cp_Utf8_big_suffix.expectLength(bigSuffixCount); cp_Utf8_big_suffix.readFrom(in); cp_Utf8_suffix.resetForSecondPass(); for (int i = 0; i < len; i++) { int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt(); int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt(); if (suffix == 0 && i >= SUFFIX_SKIP_1) { assert(suffixChars[i] == null); suffix = cp_Utf8_big_suffix.getInt(); } else { assert(suffixChars[i] != null); } if (maxChars < prefix + suffix) maxChars = prefix + suffix; } char[] buf = new char[maxChars]; // Fifth band(s): Get the specially packed characters. cp_Utf8_suffix.resetForSecondPass(); cp_Utf8_big_suffix.resetForSecondPass(); for (int i = 0; i < len; i++) { if (i < SUFFIX_SKIP_1) continue; int suffix = cp_Utf8_suffix.getInt(); if (suffix != 0) continue; // already input suffix = cp_Utf8_big_suffix.getInt(); suffixChars[i] = new char[suffix]; if (suffix == 0) { // Do not bother to add an empty "(Utf8_big_0)" band. continue; } IntBand packed = cp_Utf8_big_chars.newIntBand("(Utf8_big_"+i+")"); packed.expectLength(suffix); packed.readFrom(in); for (int j = 0; j < suffix; j++) { int ch = packed.getInt(); assert(ch == (char)ch); suffixChars[i][j] = (char)ch; } packed.doneDisbursing(); } cp_Utf8_big_chars.doneDisbursing(); // Finally, sew together all the prefixes and suffixes. cp_Utf8_prefix.resetForSecondPass(); cp_Utf8_suffix.resetForSecondPass(); cp_Utf8_big_suffix.resetForSecondPass(); for (int i = 0; i < len; i++) { int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt(); int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt(); if (suffix == 0 && i >= SUFFIX_SKIP_1) suffix = cp_Utf8_big_suffix.getInt(); // by induction, the buffer is already filled with the prefix System.arraycopy(suffixChars[i], 0, buf, prefix, suffix); cpMap[i] = ConstantPool.getUtf8Entry(new String(buf, 0, prefix+suffix)); } cp_Utf8_prefix.doneDisbursing(); cp_Utf8_suffix.doneDisbursing(); cp_Utf8_big_suffix.doneDisbursing(); } Map<Utf8Entry, SignatureEntry> utf8Signatures; void readSignatureBands(Entry[] cpMap) throws IOException { // cp_Signature: // *cp_Signature_form :DELTA5 (cp_Utf8) // *cp_Signature_classes :UDELTA5 (cp_Class) cp_Signature_form.expectLength(cpMap.length); cp_Signature_form.readFrom(in); cp_Signature_form.setIndex(getCPIndex(CONSTANT_Utf8)); int[] numSigClasses = new int[cpMap.length]; for (int i = 0; i < cpMap.length; i++) { Utf8Entry formRef = (Utf8Entry) cp_Signature_form.getRef(); numSigClasses[i] = ConstantPool.countClassParts(formRef); } cp_Signature_form.resetForSecondPass(); cp_Signature_classes.expectLength(getIntTotal(numSigClasses)); cp_Signature_classes.readFrom(in); cp_Signature_classes.setIndex(getCPIndex(CONSTANT_Class)); utf8Signatures = new HashMap<>(); for (int i = 0; i < cpMap.length; i++) { Utf8Entry formRef = (Utf8Entry) cp_Signature_form.getRef(); ClassEntry[] classRefs = new ClassEntry[numSigClasses[i]]; for (int j = 0; j < classRefs.length; j++) { classRefs[j] = (ClassEntry) cp_Signature_classes.getRef(); } SignatureEntry se = ConstantPool.getSignatureEntry(formRef, classRefs); cpMap[i] = se; utf8Signatures.put(se.asUtf8Entry(), se); } cp_Signature_form.doneDisbursing(); cp_Signature_classes.doneDisbursing(); } void readMemberRefs(byte tag, Entry[] cpMap, CPRefBand cp_class, CPRefBand cp_desc) throws IOException { // cp_Field: // *cp_Field_class :DELTA5 (cp_Class) // *cp_Field_desc :UDELTA5 (cp_Descr) // cp_Method: // *cp_Method_class :DELTA5 (cp_Class) // *cp_Method_desc :UDELTA5 (cp_Descr) // cp_Imethod: // *cp_Imethod_class :DELTA5 (cp_Class) // *cp_Imethod_desc :UDELTA5 (cp_Descr) cp_class.expectLength(cpMap.length); cp_class.readFrom(in); cp_class.setIndex(getCPIndex(CONSTANT_Class)); cp_desc.expectLength(cpMap.length); cp_desc.readFrom(in); cp_desc.setIndex(getCPIndex(CONSTANT_NameandType)); for (int i = 0; i < cpMap.length; i++) { ClassEntry mclass = (ClassEntry ) cp_class.getRef(); DescriptorEntry mdescr = (DescriptorEntry) cp_desc.getRef(); cpMap[i] = ConstantPool.getMemberEntry(tag, mclass, mdescr); } cp_class.doneDisbursing(); cp_desc.doneDisbursing(); } void readFiles() throws IOException { // file_bands: // *file_name :UNSIGNED5 (cp_Utf8) // *file_size_hi :UNSIGNED5 // *file_size_lo :UNSIGNED5 // *file_modtime :DELTA5 // *file_options :UNSIGNED5 // *file_bits :BYTE1 if (verbose > 0) Utils.log.info(" ...building "+numFiles+" files..."); file_name.expectLength(numFiles); file_size_lo.expectLength(numFiles); int options = archiveOptions; boolean haveSizeHi = testBit(options, AO_HAVE_FILE_SIZE_HI); boolean haveModtime = testBit(options, AO_HAVE_FILE_MODTIME); boolean haveOptions = testBit(options, AO_HAVE_FILE_OPTIONS); if (haveSizeHi) file_size_hi.expectLength(numFiles); if (haveModtime) file_modtime.expectLength(numFiles); if (haveOptions) file_options.expectLength(numFiles); file_name.readFrom(in); file_size_hi.readFrom(in); file_size_lo.readFrom(in); file_modtime.readFrom(in); file_options.readFrom(in); file_bits.setInputStreamFrom(in); Iterator<Class> nextClass = pkg.getClasses().iterator(); // Compute file lengths before reading any file bits. long totalFileLength = 0; long[] fileLengths = new long[numFiles]; for (int i = 0; i < numFiles; i++) { long size = ((long)file_size_lo.getInt() << 32) >>> 32; if (haveSizeHi) size += (long)file_size_hi.getInt() << 32; fileLengths[i] = size; totalFileLength += size; } assert(in.getReadLimit() == -1 || in.getReadLimit() == totalFileLength); byte[] buf = new byte[1<<16]; for (int i = 0; i < numFiles; i++) { // %%% Use a big temp file for file bits? Utf8Entry name = (Utf8Entry) file_name.getRef(); long size = fileLengths[i]; File file = pkg.new File(name); file.modtime = pkg.default_modtime; file.options = pkg.default_options; if (haveModtime) file.modtime += file_modtime.getInt(); if (haveOptions) file.options |= file_options.getInt(); if (verbose > 1) Utils.log.fine("Reading "+size+" bytes of "+name.stringValue()); long toRead = size; while (toRead > 0) { int nr = buf.length; if (nr > toRead) nr = (int) toRead; nr = file_bits.getInputStream().read(buf, 0, nr); if (nr < 0) throw new EOFException(); file.addBytes(buf, 0, nr); toRead -= nr; } pkg.addFile(file); if (file.isClassStub()) { assert(file.getFileLength() == 0); Class cls = nextClass.next(); cls.initFile(file); } } // Do the rest of the classes. while (nextClass.hasNext()) { Class cls = nextClass.next(); cls.initFile(null); // implicitly initialize to a trivial one cls.file.modtime = pkg.default_modtime; } file_name.doneDisbursing(); file_size_hi.doneDisbursing(); file_size_lo.doneDisbursing(); file_modtime.doneDisbursing(); file_options.doneDisbursing(); file_bits.doneDisbursing(); file_bands.doneDisbursing(); if (archiveSize1 != 0 && !in.atLimit()) { throw new RuntimeException("Predicted archive_size "+ archiveSize1+" != "+ (in.getBytesServed()-archiveSize0)); } } void readAttrDefs() throws IOException { // attr_definition_bands: // *attr_definition_headers :BYTE1 // *attr_definition_name :UNSIGNED5 (cp_Utf8) // *attr_definition_layout :UNSIGNED5 (cp_Utf8) attr_definition_headers.expectLength(numAttrDefs); attr_definition_name.expectLength(numAttrDefs); attr_definition_layout.expectLength(numAttrDefs); attr_definition_headers.readFrom(in); attr_definition_name.readFrom(in); attr_definition_layout.readFrom(in); try (PrintStream dump = !optDumpBands ? null : new PrintStream(getDumpStream(attr_definition_headers, ".def"))) { for (int i = 0; i < numAttrDefs; i++) { int header = attr_definition_headers.getByte(); Utf8Entry name = (Utf8Entry) attr_definition_name.getRef(); Utf8Entry layout = (Utf8Entry) attr_definition_layout.getRef(); int ctype = (header & ADH_CONTEXT_MASK); int index = (header >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB; Attribute.Layout def = new Attribute.Layout(ctype, name.stringValue(), layout.stringValue()); // Check layout string for Java 6 extensions. String pvLayout = def.layoutForClassVersion(getHighestClassVersion()); if (!pvLayout.equals(def.layout())) { throw new IOException("Bad attribute layout in archive: "+def.layout()); } this.setAttributeLayoutIndex(def, index); if (dump != null) dump.println(index+" "+def); } } attr_definition_headers.doneDisbursing(); attr_definition_name.doneDisbursing(); attr_definition_layout.doneDisbursing(); // Attribute layouts define bands, one per layout element. // Create them now, all at once. makeNewAttributeBands(); attr_definition_bands.doneDisbursing(); } void readInnerClasses() throws IOException { // ic_bands: // *ic_this_class :UDELTA5 (cp_Class) // *ic_flags :UNSIGNED5 // *ic_outer_class :DELTA5 (null or cp_Class) // *ic_name :DELTA5 (null or cp_Utf8) ic_this_class.expectLength(numInnerClasses); ic_this_class.readFrom(in); ic_flags.expectLength(numInnerClasses); ic_flags.readFrom(in); int longICCount = 0; for (int i = 0; i < numInnerClasses; i++) { int flags = ic_flags.getInt(); boolean longForm = (flags & ACC_IC_LONG_FORM) != 0; if (longForm) { longICCount += 1; } } ic_outer_class.expectLength(longICCount); ic_outer_class.readFrom(in); ic_name.expectLength(longICCount); ic_name.readFrom(in); ic_flags.resetForSecondPass(); List<InnerClass> icList = new ArrayList<>(numInnerClasses); for (int i = 0; i < numInnerClasses; i++) { int flags = ic_flags.getInt(); boolean longForm = (flags & ACC_IC_LONG_FORM) != 0; flags &= ~ACC_IC_LONG_FORM; ClassEntry thisClass = (ClassEntry) ic_this_class.getRef(); ClassEntry outerClass; Utf8Entry thisName; if (longForm) { outerClass = (ClassEntry) ic_outer_class.getRef(); thisName = (Utf8Entry) ic_name.getRef(); } else { String n = thisClass.stringValue(); String[] parse = Package.parseInnerClassName(n); assert(parse != null); String pkgOuter = parse[0]; //String number = parse[1]; String name = parse[2]; if (pkgOuter == null) outerClass = null; else outerClass = ConstantPool.getClassEntry(pkgOuter); if (name == null) thisName = null; else thisName = ConstantPool.getUtf8Entry(name); } InnerClass ic = new InnerClass(thisClass, outerClass, thisName, flags); assert(longForm || ic.predictable); icList.add(ic); } ic_flags.doneDisbursing(); ic_this_class.doneDisbursing(); ic_outer_class.doneDisbursing(); ic_name.doneDisbursing(); pkg.setAllInnerClasses(icList); ic_bands.doneDisbursing(); } void readLocalInnerClasses(Class cls) throws IOException { int nc = class_InnerClasses_N.getInt(); List<InnerClass> localICs = new ArrayList<>(nc); for (int i = 0; i < nc; i++) { ClassEntry thisClass = (ClassEntry) class_InnerClasses_RC.getRef(); int flags = class_InnerClasses_F.getInt(); if (flags == 0) { // A zero flag means copy a global IC here. InnerClass ic = pkg.getGlobalInnerClass(thisClass); assert(ic != null); // must be a valid global IC reference localICs.add(ic); } else { if (flags == ACC_IC_LONG_FORM) flags = 0; // clear the marker bit ClassEntry outer = (ClassEntry) class_InnerClasses_outer_RCN.getRef(); Utf8Entry name = (Utf8Entry) class_InnerClasses_name_RUN.getRef(); localICs.add(new InnerClass(thisClass, outer, name, flags)); } } cls.setInnerClasses(localICs); // cls.expandLocalICs may add more tuples to ics also, // or may even delete tuples. // We cannot do that now, because we do not know the // full contents of the local constant pool yet. } static final int NO_FLAGS_YET = 0; // placeholder for later flag read-in Class[] readClasses() throws IOException { // class_bands: // *class_this :DELTA5 (cp_Class) // *class_super :DELTA5 (cp_Class) // *class_interface_count :DELTA5 // *class_interface :DELTA5 (cp_Class) // ...(member bands)... // class_attr_bands // code_bands Class[] classes = new Class[numClasses]; if (verbose > 0) Utils.log.info(" ...building "+classes.length+" classes..."); class_this.expectLength(numClasses); class_super.expectLength(numClasses); class_interface_count.expectLength(numClasses); class_this.readFrom(in); class_super.readFrom(in); class_interface_count.readFrom(in); class_interface.expectLength(class_interface_count.getIntTotal()); class_interface.readFrom(in); for (int i = 0; i < classes.length; i++) { ClassEntry thisClass = (ClassEntry) class_this.getRef(); ClassEntry superClass = (ClassEntry) class_super.getRef(); ClassEntry[] interfaces = new ClassEntry[class_interface_count.getInt()]; for (int j = 0; j < interfaces.length; j++) { interfaces[j] = (ClassEntry) class_interface.getRef(); } // Packer encoded rare case of null superClass as thisClass: if (superClass == thisClass) superClass = null; Class cls = pkg.new Class(NO_FLAGS_YET, thisClass, superClass, interfaces); classes[i] = cls; } class_this.doneDisbursing(); class_super.doneDisbursing(); class_interface_count.doneDisbursing(); class_interface.doneDisbursing(); readMembers(classes); countAndReadAttrs(ATTR_CONTEXT_CLASS, Arrays.asList(classes)); pkg.trimToSize(); readCodeHeaders(); //code_bands.doneDisbursing(); // still need to read code attrs //class_bands.doneDisbursing(); // still need to read code attrs return classes; } private int getOutputIndex(Entry e) { // Output CPs do not contain signatures. assert(e.tag != CONSTANT_Signature); int k = pkg.cp.untypedIndexOf(e); // In the output ordering, input signatures can serve // in place of Utf8s. if (k >= 0) return k; if (e.tag == CONSTANT_Utf8) { Entry se = utf8Signatures.get(e); return pkg.cp.untypedIndexOf(se); } return -1; } Comparator<Entry> entryOutputOrder = new Comparator<>() { public int compare(Entry e0, Entry e1) { int k0 = getOutputIndex(e0); int k1 = getOutputIndex(e1); if (k0 >= 0 && k1 >= 0) // If both have keys, use the keys. return k0 - k1; if (k0 == k1) // If neither have keys, use their native tags & spellings. return e0.compareTo(e1); // Otherwise, the guy with the key comes first. return (k0 >= 0)? 0-1: 1-0; } }; void reconstructClass(Class cls) { if (verbose > 1) Utils.log.fine("reconstruct "+cls); // check for local .ClassFile.version Attribute retroVersion = cls.getAttribute(attrClassFileVersion); if (retroVersion != null) { cls.removeAttribute(retroVersion); cls.version = parseClassFileVersionAttr(retroVersion); } else { cls.version = pkg.defaultClassVersion; } // Replace null SourceFile by "obvious" string. cls.expandSourceFile(); // record the local cp: cls.setCPMap(reconstructLocalCPMap(cls)); } Entry[] reconstructLocalCPMap(Class cls) { Set<Entry> ldcRefs = ldcRefMap.get(cls); Set<Entry> cpRefs = new HashSet<>(); // look for constant pool entries: cls.visitRefs(VRM_CLASSIC, cpRefs); ArrayList<BootstrapMethodEntry> bsms = new ArrayList<>(); // flesh out the local constant pool ConstantPool.completeReferencesIn(cpRefs, true, bsms); // add the bsm and references as required if (!bsms.isEmpty()) { cls.addAttribute(Package.attrBootstrapMethodsEmpty.canonicalInstance()); cpRefs.add(Package.getRefString("BootstrapMethods")); Collections.sort(bsms); cls.setBootstrapMethods(bsms); } // Now that we know all our local class references, // compute the InnerClasses attribute. // An InnerClasses attribute usually gets added here, // although it might already have been present. int changed = cls.expandLocalICs(); if (changed != 0) { if (changed > 0) { // Just visit the expanded InnerClasses attr. cls.visitInnerClassRefs(VRM_CLASSIC, cpRefs); } else { // Have to recompute from scratch, because of deletions. cpRefs.clear(); cls.visitRefs(VRM_CLASSIC, cpRefs); } // flesh out the local constant pool, again ConstantPool.completeReferencesIn(cpRefs, true, bsms); } // construct a local constant pool int numDoubles = 0; for (Entry e : cpRefs) { if (e.isDoubleWord()) numDoubles++; } Entry[] cpMap = new Entry[1+numDoubles+cpRefs.size()]; int fillp = 1; // Add all ldc operands first. if (ldcRefs != null) { assert(cpRefs.containsAll(ldcRefs)); for (Entry e : ldcRefs) { cpMap[fillp++] = e; } assert(fillp == 1+ldcRefs.size()); cpRefs.removeAll(ldcRefs); ldcRefs = null; // done with it } // Next add all the two-byte references. Set<Entry> wideRefs = cpRefs; cpRefs = null; // do not use! int narrowLimit = fillp; for (Entry e : wideRefs) { cpMap[fillp++] = e; } assert(fillp == narrowLimit+wideRefs.size()); Arrays.sort(cpMap, 1, narrowLimit, entryOutputOrder); Arrays.sort(cpMap, narrowLimit, fillp, entryOutputOrder); if (verbose > 3) { Utils.log.fine("CP of "+this+" {"); for (int i = 0; i < fillp; i++) { Entry e = cpMap[i]; Utils.log.fine(" "+((e==null)?-1:getOutputIndex(e)) +" : "+e); } Utils.log.fine("}"); } // Now repack backwards, introducing null elements. int revp = cpMap.length; for (int i = fillp; --i >= 1; ) { Entry e = cpMap[i]; if (e.isDoubleWord()) cpMap[--revp] = null; cpMap[--revp] = e; } assert(revp == 1); // do not process the initial null return cpMap; } void readMembers(Class[] classes) throws IOException { // class_bands: // ... // *class_field_count :DELTA5 // *class_method_count :DELTA5 // // *field_descr :DELTA5 (cp_Descr) // field_attr_bands // // *method_descr :MDELTA5 (cp_Descr) // method_attr_bands // ... assert(classes.length == numClasses); class_field_count.expectLength(numClasses); class_method_count.expectLength(numClasses); class_field_count.readFrom(in); class_method_count.readFrom(in); // Make a pre-pass over field and method counts to size the descrs: int totalNF = class_field_count.getIntTotal(); int totalNM = class_method_count.getIntTotal(); field_descr.expectLength(totalNF); method_descr.expectLength(totalNM); if (verbose > 1) Utils.log.fine("expecting #fields="+totalNF+ " and #methods="+totalNM+" in #classes="+numClasses); List<Class.Field> fields = new ArrayList<>(totalNF); field_descr.readFrom(in); for (int i = 0; i < classes.length; i++) { Class c = classes[i]; int nf = class_field_count.getInt(); for (int j = 0; j < nf; j++) { Class.Field f = c.new Field(NO_FLAGS_YET, (DescriptorEntry) field_descr.getRef()); fields.add(f); } } class_field_count.doneDisbursing(); field_descr.doneDisbursing(); countAndReadAttrs(ATTR_CONTEXT_FIELD, fields); fields = null; // release to GC List<Class.Method> methods = new ArrayList<>(totalNM); method_descr.readFrom(in); for (int i = 0; i < classes.length; i++) { Class c = classes[i]; int nm = class_method_count.getInt(); for (int j = 0; j < nm; j++) { Class.Method m = c.new Method(NO_FLAGS_YET, (DescriptorEntry) method_descr.getRef()); methods.add(m); } } class_method_count.doneDisbursing(); method_descr.doneDisbursing(); countAndReadAttrs(ATTR_CONTEXT_METHOD, methods); // Up to this point, Code attributes look like empty attributes. // Now we start to special-case them. The empty canonical Code // attributes stay in the method attribute lists, however. allCodes = buildCodeAttrs(methods); } Code[] allCodes; List<Code> codesWithFlags; Map<Class, Set<Entry>> ldcRefMap = new HashMap<>(); Code[] buildCodeAttrs(List<Class.Method> methods) { List<Code> codes = new ArrayList<>(methods.size()); for (Class.Method m : methods) { if (m.getAttribute(attrCodeEmpty) != null) { m.code = new Code(m); codes.add(m.code); } } Code[] a = new Code[codes.size()]; codes.toArray(a); return a; } void readCodeHeaders() throws IOException { // code_bands: // *code_headers :BYTE1 // // *code_max_stack :UNSIGNED5 // *code_max_na_locals :UNSIGNED5 // *code_handler_count :UNSIGNED5 // ... // code_attr_bands boolean attrsOK = testBit(archiveOptions, AO_HAVE_ALL_CODE_FLAGS); code_headers.expectLength(allCodes.length); code_headers.readFrom(in); List<Code> longCodes = new ArrayList<>(allCodes.length / 10); for (int i = 0; i < allCodes.length; i++) { Code c = allCodes[i]; int sc = code_headers.getByte(); assert(sc == (sc & 0xFF)); if (verbose > 2) Utils.log.fine("codeHeader "+c+" = "+sc); if (sc == LONG_CODE_HEADER) { // We will read ms/ml/nh/flags from bands shortly. longCodes.add(c); continue; } // Short code header is the usual case: c.setMaxStack( shortCodeHeader_max_stack(sc) ); c.setMaxNALocals( shortCodeHeader_max_na_locals(sc) ); c.setHandlerCount( shortCodeHeader_handler_count(sc) ); assert(shortCodeHeader(c) == sc); } code_headers.doneDisbursing(); code_max_stack.expectLength(longCodes.size()); code_max_na_locals.expectLength(longCodes.size()); code_handler_count.expectLength(longCodes.size()); // Do the long headers now. code_max_stack.readFrom(in); code_max_na_locals.readFrom(in); code_handler_count.readFrom(in); for (Code c : longCodes) { c.setMaxStack( code_max_stack.getInt() ); c.setMaxNALocals( code_max_na_locals.getInt() ); c.setHandlerCount( code_handler_count.getInt() ); } code_max_stack.doneDisbursing(); code_max_na_locals.doneDisbursing(); code_handler_count.doneDisbursing(); readCodeHandlers(); if (attrsOK) { // Code attributes are common (debug info not stripped). codesWithFlags = Arrays.asList(allCodes); } else { // Code attributes are very sparse (debug info is stripped). codesWithFlags = longCodes; } countAttrs(ATTR_CONTEXT_CODE, codesWithFlags); // do readAttrs later, after BCs are scanned } void readCodeHandlers() throws IOException { // code_bands: // ... // *code_handler_start_P :BCI5 // *code_handler_end_PO :BRANCH5 // *code_handler_catch_PO :BRANCH5 // *code_handler_class_RCN :UNSIGNED5 (null or cp_Class) // ... int nh = 0; for (int i = 0; i < allCodes.length; i++) { Code c = allCodes[i]; nh += c.getHandlerCount(); } ValueBand[] code_handler_bands = { code_handler_start_P, code_handler_end_PO, code_handler_catch_PO, code_handler_class_RCN }; for (int i = 0; i < code_handler_bands.length; i++) { code_handler_bands[i].expectLength(nh); code_handler_bands[i].readFrom(in); } for (int i = 0; i < allCodes.length; i++) { Code c = allCodes[i]; for (int j = 0, jmax = c.getHandlerCount(); j < jmax; j++) { c.handler_class[j] = code_handler_class_RCN.getRef(); // For now, just record the raw BCI codes. // We must wait until we have instruction boundaries. c.handler_start[j] = code_handler_start_P.getInt(); c.handler_end[j] = code_handler_end_PO.getInt(); c.handler_catch[j] = code_handler_catch_PO.getInt(); } } for (int i = 0; i < code_handler_bands.length; i++) { code_handler_bands[i].doneDisbursing(); } } void fixupCodeHandlers() { // Actually decode (renumber) the BCIs now. for (int i = 0; i < allCodes.length; i++) { Code c = allCodes[i]; for (int j = 0, jmax = c.getHandlerCount(); j < jmax; j++) { int sum = c.handler_start[j]; c.handler_start[j] = c.decodeBCI(sum); sum += c.handler_end[j]; c.handler_end[j] = c.decodeBCI(sum); sum += c.handler_catch[j]; c.handler_catch[j] = c.decodeBCI(sum); } } } // Generic routines for reading attributes of // classes, fields, methods, and codes. // The holders is a global list, already collected, // of attribute "customers". void countAndReadAttrs(int ctype, Collection<? extends Attribute.Holder> holders) throws IOException { // class_attr_bands: // *class_flags :UNSIGNED5 // *class_attr_count :UNSIGNED5 // *class_attr_indexes :UNSIGNED5 // *class_attr_calls :UNSIGNED5 // *class_Signature_RS :UNSIGNED5 (cp_Signature) // class_metadata_bands // *class_SourceFile_RU :UNSIGNED5 (cp_Utf8) // *class_EnclosingMethod_RM :UNSIGNED5 (cp_Method) // ic_local_bands // *class_ClassFile_version_minor_H :UNSIGNED5 // *class_ClassFile_version_major_H :UNSIGNED5 // class_type_metadata_bands // // field_attr_bands: // *field_flags :UNSIGNED5 // *field_attr_count :UNSIGNED5 // *field_attr_indexes :UNSIGNED5 // *field_attr_calls :UNSIGNED5 // *field_Signature_RS :UNSIGNED5 (cp_Signature) // field_metadata_bands // *field_ConstantValue_KQ :UNSIGNED5 (cp_Int, etc.; see note) // field_type_metadata_bands // // method_attr_bands: // *method_flags :UNSIGNED5 // *method_attr_count :UNSIGNED5 // *method_attr_indexes :UNSIGNED5 // *method_attr_calls :UNSIGNED5 // *method_Signature_RS :UNSIGNED5 (cp_Signature) // method_metadata_bands // *method_Exceptions_N :UNSIGNED5 // *method_Exceptions_RC :UNSIGNED5 (cp_Class) // *method_MethodParameters_NB: BYTE1 // *method_MethodParameters_RUN: UNSIGNED5 (cp_Utf8) // *method_MethodParameters_FH: UNSIGNED5 (flag) // method_type_metadata_bands // // code_attr_bands: // *code_flags :UNSIGNED5 // *code_attr_count :UNSIGNED5 // *code_attr_indexes :UNSIGNED5 // *code_attr_calls :UNSIGNED5 // *code_LineNumberTable_N :UNSIGNED5 // *code_LineNumberTable_bci_P :BCI5 // *code_LineNumberTable_line :UNSIGNED5 // *code_LocalVariableTable_N :UNSIGNED5 // *code_LocalVariableTable_bci_P :BCI5 // *code_LocalVariableTable_span_O :BRANCH5 // *code_LocalVariableTable_name_RU :UNSIGNED5 (cp_Utf8) // *code_LocalVariableTable_type_RS :UNSIGNED5 (cp_Signature) // *code_LocalVariableTable_slot :UNSIGNED5 // code_type_metadata_bands countAttrs(ctype, holders); readAttrs(ctype, holders); } // Read flags and count the attributes that are to be placed // on the given holders. void countAttrs(int ctype, Collection<? extends Attribute.Holder> holders) throws IOException { // Here, xxx stands for one of class, field, method, code. MultiBand xxx_attr_bands = attrBands[ctype]; long flagMask = attrFlagMask[ctype]; if (verbose > 1) { Utils.log.fine("scanning flags and attrs for "+ Attribute.contextName(ctype)+"["+holders.size()+"]"); } // Fetch the attribute layout definitions which govern the bands // we are about to read. List<Attribute.Layout> defList = attrDefs.get(ctype); Attribute.Layout[] defs = new Attribute.Layout[defList.size()]; defList.toArray(defs); IntBand xxx_flags_hi = getAttrBand(xxx_attr_bands, AB_FLAGS_HI); IntBand xxx_flags_lo = getAttrBand(xxx_attr_bands, AB_FLAGS_LO); IntBand xxx_attr_count = getAttrBand(xxx_attr_bands, AB_ATTR_COUNT); IntBand xxx_attr_indexes = getAttrBand(xxx_attr_bands, AB_ATTR_INDEXES); IntBand xxx_attr_calls = getAttrBand(xxx_attr_bands, AB_ATTR_CALLS); // Count up the number of holders which have overflow attrs. int overflowMask = attrOverflowMask[ctype]; int overflowHolderCount = 0; boolean haveLongFlags = haveFlagsHi(ctype); xxx_flags_hi.expectLength(haveLongFlags? holders.size(): 0); xxx_flags_hi.readFrom(in); xxx_flags_lo.expectLength(holders.size()); xxx_flags_lo.readFrom(in); assert((flagMask & overflowMask) == overflowMask); for (Attribute.Holder h : holders) { int flags = xxx_flags_lo.getInt(); h.flags = flags; if ((flags & overflowMask) != 0) overflowHolderCount += 1; } // For each holder with overflow attrs, read a count. xxx_attr_count.expectLength(overflowHolderCount); xxx_attr_count.readFrom(in); xxx_attr_indexes.expectLength(xxx_attr_count.getIntTotal()); xxx_attr_indexes.readFrom(in); // Now it's time to check flag bits that indicate attributes. // We accumulate (a) a list of attribute types for each holder // (class/field/method/code), and also we accumulate (b) a total // count for each attribute type. int[] totalCounts = new int[defs.length]; for (Attribute.Holder h : holders) { assert(h.attributes == null); // System.out.println("flags="+h.flags+" using fm="+flagMask); long attrBits = ((h.flags & flagMask) << 32) >>> 32; // Clean up the flags now. h.flags -= (int)attrBits; // strip attr bits assert(h.flags == (char)h.flags); // 16 bits only now assert((ctype != ATTR_CONTEXT_CODE) || h.flags == 0); if (haveLongFlags) attrBits += (long)xxx_flags_hi.getInt() << 32; if (attrBits == 0) continue; // no attrs on this guy int noa = 0; // number of overflow attrs long overflowBit = (attrBits & overflowMask); assert(overflowBit >= 0); attrBits -= overflowBit; if (overflowBit != 0) { noa = xxx_attr_count.getInt(); } int nfa = 0; // number of flag attrs long bits = attrBits; for (int ai = 0; bits != 0; ai++) { if ((bits & (1L<<ai)) == 0) continue; bits -= (1L<<ai); nfa += 1; } List<Attribute> ha = new ArrayList<>(nfa + noa); h.attributes = ha; bits = attrBits; // iterate again for (int ai = 0; bits != 0; ai++) { if ((bits & (1L<<ai)) == 0) continue; bits -= (1L<<ai); totalCounts[ai] += 1; // This definition index is live in this holder. if (defs[ai] == null) badAttrIndex(ai, ctype); Attribute canonical = defs[ai].canonicalInstance(); ha.add(canonical); nfa -= 1; } assert(nfa == 0); for (; noa > 0; noa--) { int ai = xxx_attr_indexes.getInt(); totalCounts[ai] += 1; // This definition index is live in this holder. if (defs[ai] == null) badAttrIndex(ai, ctype); Attribute canonical = defs[ai].canonicalInstance(); ha.add(canonical); } } xxx_flags_hi.doneDisbursing(); xxx_flags_lo.doneDisbursing(); xxx_attr_count.doneDisbursing(); xxx_attr_indexes.doneDisbursing(); // Now each holder has a list of canonical attribute instances. // For layouts with no elements, we are done. However, for // layouts with bands, we must replace each canonical (empty) // instance with a value-bearing one, initialized from the // appropriate bands. // Make a small pass to detect and read backward call counts. int callCounts = 0; for (boolean predef = true; ; predef = false) { for (int ai = 0; ai < defs.length; ai++) { Attribute.Layout def = defs[ai]; if (def == null) continue; // unused index if (predef != isPredefinedAttr(ctype, ai)) continue; // wrong pass int totalCount = totalCounts[ai]; if (totalCount == 0) continue; // irrelevant Attribute.Layout.Element[] cbles = def.getCallables(); for (int j = 0; j < cbles.length; j++) { assert(cbles[j].kind == Attribute.EK_CBLE); if (cbles[j].flagTest(Attribute.EF_BACK)) callCounts += 1; } } if (!predef) break; } xxx_attr_calls.expectLength(callCounts); xxx_attr_calls.readFrom(in); // Finally, size all the attribute bands. for (boolean predef = true; ; predef = false) { for (int ai = 0; ai < defs.length; ai++) { Attribute.Layout def = defs[ai]; if (def == null) continue; // unused index if (predef != isPredefinedAttr(ctype, ai)) continue; // wrong pass int totalCount = totalCounts[ai]; Band[] ab = attrBandTable.get(def); if (def == attrInnerClassesEmpty) { // Special case. // Size the bands as if using the following layout: // [RCH TI[ (0)[] ()[RCNH RUNH] ]]. class_InnerClasses_N.expectLength(totalCount); class_InnerClasses_N.readFrom(in); int tupleCount = class_InnerClasses_N.getIntTotal(); class_InnerClasses_RC.expectLength(tupleCount); class_InnerClasses_RC.readFrom(in); class_InnerClasses_F.expectLength(tupleCount); class_InnerClasses_F.readFrom(in); // Drop remaining columns wherever flags are zero: tupleCount -= class_InnerClasses_F.getIntCount(0); class_InnerClasses_outer_RCN.expectLength(tupleCount); class_InnerClasses_outer_RCN.readFrom(in); class_InnerClasses_name_RUN.expectLength(tupleCount); class_InnerClasses_name_RUN.readFrom(in); } else if (!optDebugBands && totalCount == 0) { // Expect no elements at all. Skip quickly. however if we // are debugging bands, read all bands regardless for (int j = 0; j < ab.length; j++) { ab[j].doneWithUnusedBand(); } } else { // Read these bands in sequence. boolean hasCallables = def.hasCallables(); if (!hasCallables) { readAttrBands(def.elems, totalCount, new int[0], ab); } else { Attribute.Layout.Element[] cbles = def.getCallables(); // At first, record initial calls. // Later, forward calls may also accumulate here: int[] forwardCounts = new int[cbles.length]; forwardCounts[0] = totalCount; for (int j = 0; j < cbles.length; j++) { assert(cbles[j].kind == Attribute.EK_CBLE); int entryCount = forwardCounts[j]; forwardCounts[j] = -1; // No more, please! if (totalCount > 0 && cbles[j].flagTest(Attribute.EF_BACK)) entryCount += xxx_attr_calls.getInt(); readAttrBands(cbles[j].body, entryCount, forwardCounts, ab); } } // mark them read, to satisfy asserts if (optDebugBands && totalCount == 0) { for (int j = 0; j < ab.length; j++) { ab[j].doneDisbursing(); } } } } if (!predef) break; } xxx_attr_calls.doneDisbursing(); } void badAttrIndex(int ai, int ctype) throws IOException { throw new IOException("Unknown attribute index "+ai+" for "+ ATTR_CONTEXT_NAME[ctype]+" attribute"); } void readAttrs(int ctype, Collection<? extends Attribute.Holder> holders) throws IOException { // Decode band values into attributes. Set<Attribute.Layout> sawDefs = new HashSet<>(); ByteArrayOutputStream buf = new ByteArrayOutputStream(); for (final Attribute.Holder h : holders) { if (h.attributes == null) continue; for (ListIterator<Attribute> j = h.attributes.listIterator(); j.hasNext(); ) { Attribute a = j.next(); Attribute.Layout def = a.layout(); if (def.bandCount == 0) { if (def == attrInnerClassesEmpty) { // Special logic to read this attr. readLocalInnerClasses((Class) h); continue; } // Canonical empty attr works fine (e.g., Synthetic). continue; } sawDefs.add(def); boolean isCV = (ctype == ATTR_CONTEXT_FIELD && def == attrConstantValue); if (isCV) setConstantValueIndex((Class.Field)h); if (verbose > 2) Utils.log.fine("read "+a+" in "+h); final Band[] ab = attrBandTable.get(def); // Read one attribute of type def from ab into a byte array. buf.reset(); Object fixups = a.unparse(new Attribute.ValueStream() { public int getInt(int bandIndex) { return ((IntBand) ab[bandIndex]).getInt(); } public Entry getRef(int bandIndex) { return ((CPRefBand) ab[bandIndex]).getRef(); } public int decodeBCI(int bciCode) { Code code = (Code) h; return code.decodeBCI(bciCode); } }, buf); // Replace the canonical attr with the one just read. j.set(a.addContent(buf.toByteArray(), fixups)); if (isCV) setConstantValueIndex(null); // clean up } } // Mark the bands we just used as done disbursing. for (Attribute.Layout def : sawDefs) { if (def == null) continue; // unused index Band[] ab = attrBandTable.get(def); for (int j = 0; j < ab.length; j++) { ab[j].doneDisbursing(); } } if (ctype == ATTR_CONTEXT_CLASS) { class_InnerClasses_N.doneDisbursing(); class_InnerClasses_RC.doneDisbursing(); class_InnerClasses_F.doneDisbursing(); class_InnerClasses_outer_RCN.doneDisbursing(); class_InnerClasses_name_RUN.doneDisbursing(); } MultiBand xxx_attr_bands = attrBands[ctype]; for (int i = 0; i < xxx_attr_bands.size(); i++) { Band b = xxx_attr_bands.get(i); if (b instanceof MultiBand) b.doneDisbursing(); } xxx_attr_bands.doneDisbursing(); } private void readAttrBands(Attribute.Layout.Element[] elems, int count, int[] forwardCounts, Band[] ab) throws IOException { for (int i = 0; i < elems.length; i++) { Attribute.Layout.Element e = elems[i]; Band eBand = null; if (e.hasBand()) { eBand = ab[e.bandIndex]; eBand.expectLength(count); eBand.readFrom(in); } switch (e.kind) { case Attribute.EK_REPL: // Recursive call. int repCount = ((IntBand)eBand).getIntTotal(); // Note: getIntTotal makes an extra pass over this band. readAttrBands(e.body, repCount, forwardCounts, ab); break; case Attribute.EK_UN: int remainingCount = count; for (int j = 0; j < e.body.length; j++) { int caseCount; if (j == e.body.length-1) { caseCount = remainingCount; } else { caseCount = 0; for (int j0 = j; (j == j0) || (j < e.body.length && e.body[j].flagTest(Attribute.EF_BACK)); j++) { caseCount += ((IntBand)eBand).getIntCount(e.body[j].value); } --j; // back up to last occurrence of this body } remainingCount -= caseCount; readAttrBands(e.body[j].body, caseCount, forwardCounts, ab); } assert(remainingCount == 0); break; case Attribute.EK_CALL: assert(e.body.length == 1); assert(e.body[0].kind == Attribute.EK_CBLE); if (!e.flagTest(Attribute.EF_BACK)) { // Backward calls are pre-counted, but forwards are not. // Push the present count forward. assert(forwardCounts[e.value] >= 0); forwardCounts[e.value] += count; } break; case Attribute.EK_CBLE: assert(false); break; } } } void readByteCodes() throws IOException { // bc_bands: // *bc_codes :BYTE1 // *bc_case_count :UNSIGNED5 // *bc_case_value :DELTA5 // *bc_byte :BYTE1 // *bc_short :DELTA5 // *bc_local :UNSIGNED5 // *bc_label :BRANCH5 // *bc_intref :DELTA5 (cp_Int) // *bc_floatref :DELTA5 (cp_Float) // *bc_longref :DELTA5 (cp_Long) // *bc_doubleref :DELTA5 (cp_Double) // *bc_stringref :DELTA5 (cp_String) // *bc_classref :UNSIGNED5 (current class or cp_Class) // *bc_fieldref :DELTA5 (cp_Field) // *bc_methodref :UNSIGNED5 (cp_Method) // *bc_imethodref :DELTA5 (cp_Imethod) // *bc_thisfield :UNSIGNED5 (cp_Field, only for current class) // *bc_superfield :UNSIGNED5 (cp_Field, only for current super) // *bc_thismethod :UNSIGNED5 (cp_Method, only for current class) // *bc_supermethod :UNSIGNED5 (cp_Method, only for current super) // *bc_initref :UNSIGNED5 (cp_Field, only for most recent new) // *bc_escref :UNSIGNED5 (cp_All) // *bc_escrefsize :UNSIGNED5 // *bc_escsize :UNSIGNED5 // *bc_escbyte :BYTE1 bc_codes.elementCountForDebug = allCodes.length; bc_codes.setInputStreamFrom(in); readByteCodeOps(); // reads from bc_codes and bc_case_count bc_codes.doneDisbursing(); // All the operand bands have now been sized. Read them all in turn. Band[] operand_bands = { bc_case_value, bc_byte, bc_short, bc_local, bc_label, bc_intref, bc_floatref, bc_longref, bc_doubleref, bc_stringref, bc_loadablevalueref, bc_classref, bc_fieldref, bc_methodref, bc_imethodref, bc_indyref, bc_thisfield, bc_superfield, bc_thismethod, bc_supermethod, bc_initref, bc_escref, bc_escrefsize, bc_escsize }; for (int i = 0; i < operand_bands.length; i++) { operand_bands[i].readFrom(in); } bc_escbyte.expectLength(bc_escsize.getIntTotal()); bc_escbyte.readFrom(in); expandByteCodeOps(); // Done fetching values from operand bands: bc_case_count.doneDisbursing(); for (int i = 0; i < operand_bands.length; i++) { operand_bands[i].doneDisbursing(); } bc_escbyte.doneDisbursing(); bc_bands.doneDisbursing(); // We must delay the parsing of Code attributes until we // have a complete model of bytecodes, for BCI encodings. readAttrs(ATTR_CONTEXT_CODE, codesWithFlags); // Ditto for exception handlers in codes. fixupCodeHandlers(); // Now we can finish with class_bands; cf. readClasses(). code_bands.doneDisbursing(); class_bands.doneDisbursing(); } private void readByteCodeOps() throws IOException { // scratch buffer for collecting code:: byte[] buf = new byte[1<<12]; // record of all switch opcodes (these are variable-length) List<Integer> allSwitchOps = new ArrayList<>(); for (int k = 0; k < allCodes.length; k++) { Code c = allCodes[k]; scanOneMethod: for (int i = 0; ; i++) { int bc = bc_codes.getByte(); if (i + 10 > buf.length) buf = realloc(buf); buf[i] = (byte)bc; boolean isWide = false; if (bc == _wide) { bc = bc_codes.getByte(); buf[++i] = (byte)bc; isWide = true; } assert(bc == (0xFF & bc)); // Adjust expectations of various band sizes. switch (bc) { case _tableswitch: case _lookupswitch: bc_case_count.expectMoreLength(1); allSwitchOps.add(bc); break; case _iinc: bc_local.expectMoreLength(1); if (isWide) bc_short.expectMoreLength(1); else bc_byte.expectMoreLength(1); break; case _sipush: bc_short.expectMoreLength(1); break; case _bipush: bc_byte.expectMoreLength(1); break; case _newarray: bc_byte.expectMoreLength(1); break; case _multianewarray: assert(getCPRefOpBand(bc) == bc_classref); bc_classref.expectMoreLength(1); bc_byte.expectMoreLength(1); break; case _ref_escape: bc_escrefsize.expectMoreLength(1); bc_escref.expectMoreLength(1); break; case _byte_escape: bc_escsize.expectMoreLength(1); // bc_escbyte will have to be counted too break; default: if (Instruction.isInvokeInitOp(bc)) { bc_initref.expectMoreLength(1); break; } if (Instruction.isSelfLinkerOp(bc)) { CPRefBand bc_which = selfOpRefBand(bc); bc_which.expectMoreLength(1); break; } if (Instruction.isBranchOp(bc)) { bc_label.expectMoreLength(1); break; } if (Instruction.isCPRefOp(bc)) { CPRefBand bc_which = getCPRefOpBand(bc); bc_which.expectMoreLength(1); assert(bc != _multianewarray); // handled elsewhere break; } if (Instruction.isLocalSlotOp(bc)) { bc_local.expectMoreLength(1); break; } break; case _end_marker: { // Transfer from buf to a more permanent place: c.bytes = realloc(buf, i); break scanOneMethod; } } } } // To size instruction bands correctly, we need info on switches: bc_case_count.readFrom(in); for (Integer i : allSwitchOps) { int bc = i.intValue(); int caseCount = bc_case_count.getInt(); bc_label.expectMoreLength(1+caseCount); // default label + cases bc_case_value.expectMoreLength(bc == _tableswitch ? 1 : caseCount); } bc_case_count.resetForSecondPass(); } private void expandByteCodeOps() throws IOException { // scratch buffer for collecting code: byte[] buf = new byte[1<<12]; // scratch buffer for collecting instruction boundaries: int[] insnMap = new int[1<<12]; // list of label carriers, for label decoding post-pass: int[] labels = new int[1<<10]; // scratch buffer for registering CP refs: Fixups fixupBuf = new Fixups(); for (int k = 0; k < allCodes.length; k++) { Code code = allCodes[k]; byte[] codeOps = code.bytes; code.bytes = null; // just for now, while we accumulate bits Class curClass = code.thisClass(); Set<Entry> ldcRefSet = ldcRefMap.get(curClass); if (ldcRefSet == null) ldcRefMap.put(curClass, ldcRefSet = new HashSet<>()); ClassEntry thisClass = curClass.thisClass; ClassEntry superClass = curClass.superClass; ClassEntry newClass = null; // class of last _new opcode int pc = 0; // fill pointer in buf; actual bytecode PC int numInsns = 0; int numLabels = 0; boolean hasEscs = false; fixupBuf.clear(); for (int i = 0; i < codeOps.length; i++) { int bc = Instruction.getByte(codeOps, i); int curPC = pc; insnMap[numInsns++] = curPC; if (pc + 10 > buf.length) buf = realloc(buf); if (numInsns+10 > insnMap.length) insnMap = realloc(insnMap); if (numLabels+10 > labels.length) labels = realloc(labels); boolean isWide = false; if (bc == _wide) { buf[pc++] = (byte) bc; bc = Instruction.getByte(codeOps, ++i); isWide = true; } switch (bc) { case _tableswitch: // apc: (df, lo, hi, (hi-lo+1)*(label)) case _lookupswitch: // apc: (df, nc, nc*(case, label)) { int caseCount = bc_case_count.getInt(); while ((pc + 30 + caseCount*8) > buf.length) buf = realloc(buf); buf[pc++] = (byte) bc; //initialize apc, df, lo, hi bytes to reasonable bits: Arrays.fill(buf, pc, pc+30, (byte)0); Instruction.Switch isw = (Instruction.Switch) Instruction.at(buf, curPC); //isw.setDefaultLabel(getLabel(bc_label, code, curPC)); isw.setCaseCount(caseCount); if (bc == _tableswitch) { isw.setCaseValue(0, bc_case_value.getInt()); } else { for (int j = 0; j < caseCount; j++) { isw.setCaseValue(j, bc_case_value.getInt()); } } // Make our getLabel calls later. labels[numLabels++] = curPC; pc = isw.getNextPC(); continue; } case _iinc: { buf[pc++] = (byte) bc; int local = bc_local.getInt(); int delta; if (isWide) { delta = bc_short.getInt(); Instruction.setShort(buf, pc, local); pc += 2; Instruction.setShort(buf, pc, delta); pc += 2; } else { delta = (byte) bc_byte.getByte(); buf[pc++] = (byte)local; buf[pc++] = (byte)delta; } continue; } case _sipush: { int val = bc_short.getInt(); buf[pc++] = (byte) bc; Instruction.setShort(buf, pc, val); pc += 2; continue; } case _bipush: case _newarray: { int val = bc_byte.getByte(); buf[pc++] = (byte) bc; buf[pc++] = (byte) val; continue; } case _ref_escape: { // Note that insnMap has one entry for this. hasEscs = true; int size = bc_escrefsize.getInt(); Entry ref = bc_escref.getRef(); if (size == 1) ldcRefSet.add(ref); int fmt; switch (size) { case 1: fixupBuf.addU1(pc, ref); break; case 2: fixupBuf.addU2(pc, ref); break; default: assert(false); fmt = 0; } buf[pc+0] = buf[pc+1] = 0; pc += size; } continue; case _byte_escape: { // Note that insnMap has one entry for all these bytes. hasEscs = true; int size = bc_escsize.getInt(); while ((pc + size) > buf.length) buf = realloc(buf); while (size-- > 0) { buf[pc++] = (byte) bc_escbyte.getByte(); } } continue; default: if (Instruction.isInvokeInitOp(bc)) { int idx = (bc - _invokeinit_op); int origBC = _invokespecial; ClassEntry classRef; switch (idx) { case _invokeinit_self_option: classRef = thisClass; break; case _invokeinit_super_option: classRef = superClass; break; default: assert(idx == _invokeinit_new_option); classRef = newClass; break; } buf[pc++] = (byte) origBC; int coding = bc_initref.getInt(); // Find the nth overloading of <init> in classRef. MemberEntry ref = pkg.cp.getOverloadingForIndex(CONSTANT_Methodref, classRef, "<init>", coding); fixupBuf.addU2(pc, ref); buf[pc+0] = buf[pc+1] = 0; pc += 2; assert(Instruction.opLength(origBC) == (pc - curPC)); continue; } if (Instruction.isSelfLinkerOp(bc)) { int idx = (bc - _self_linker_op); boolean isSuper = (idx >= _self_linker_super_flag); if (isSuper) idx -= _self_linker_super_flag; boolean isAload = (idx >= _self_linker_aload_flag); if (isAload) idx -= _self_linker_aload_flag; int origBC = _first_linker_op + idx; boolean isField = Instruction.isFieldOp(origBC); CPRefBand bc_which; ClassEntry which_cls = isSuper ? superClass : thisClass; Index which_ix; if (isField) { bc_which = isSuper ? bc_superfield : bc_thisfield; which_ix = pkg.cp.getMemberIndex(CONSTANT_Fieldref, which_cls); } else { bc_which = isSuper ? bc_supermethod : bc_thismethod; which_ix = pkg.cp.getMemberIndex(CONSTANT_Methodref, which_cls); } assert(bc_which == selfOpRefBand(bc)); MemberEntry ref = (MemberEntry) bc_which.getRef(which_ix); if (isAload) { buf[pc++] = (byte) _aload_0; curPC = pc; // Note: insnMap keeps the _aload_0 separate. insnMap[numInsns++] = curPC; } buf[pc++] = (byte) origBC; fixupBuf.addU2(pc, ref); buf[pc+0] = buf[pc+1] = 0; pc += 2; assert(Instruction.opLength(origBC) == (pc - curPC)); continue; } if (Instruction.isBranchOp(bc)) { buf[pc++] = (byte) bc; assert(!isWide); // no wide prefix for branches int nextPC = curPC + Instruction.opLength(bc); // Make our getLabel calls later. labels[numLabels++] = curPC; //Instruction.at(buf, curPC).setBranchLabel(getLabel(bc_label, code, curPC)); while (pc < nextPC) buf[pc++] = 0; continue; } if (Instruction.isCPRefOp(bc)) { CPRefBand bc_which = getCPRefOpBand(bc); Entry ref = bc_which.getRef(); if (ref == null) { if (bc_which == bc_classref) { // Shorthand for class self-references. ref = thisClass; } else { assert(false); } } int origBC = bc; int size = 2; switch (bc) { case _invokestatic_int: origBC = _invokestatic; break; case _invokespecial_int: origBC = _invokespecial; break; case _ildc: case _cldc: case _fldc: case _sldc: case _qldc: origBC = _ldc; size = 1; ldcRefSet.add(ref); break; case _ildc_w: case _cldc_w: case _fldc_w: case _sldc_w: case _qldc_w: origBC = _ldc_w; break; case _lldc2_w: case _dldc2_w: origBC = _ldc2_w; break; case _new: newClass = (ClassEntry) ref; break; } buf[pc++] = (byte) origBC; int fmt; switch (size) { case 1: fixupBuf.addU1(pc, ref); break; case 2: fixupBuf.addU2(pc, ref); break; default: assert(false); fmt = 0; } buf[pc+0] = buf[pc+1] = 0; pc += size; if (origBC == _multianewarray) { // Copy the trailing byte also. int val = bc_byte.getByte(); buf[pc++] = (byte) val; } else if (origBC == _invokeinterface) { int argSize = ((MemberEntry)ref).descRef.typeRef.computeSize(true); buf[pc++] = (byte)( 1 + argSize ); buf[pc++] = 0; } else if (origBC == _invokedynamic) { buf[pc++] = 0; buf[pc++] = 0; } assert(Instruction.opLength(origBC) == (pc - curPC)); continue; } if (Instruction.isLocalSlotOp(bc)) { buf[pc++] = (byte) bc; int local = bc_local.getInt(); if (isWide) { Instruction.setShort(buf, pc, local); pc += 2; if (bc == _iinc) { int iVal = bc_short.getInt(); Instruction.setShort(buf, pc, iVal); pc += 2; } } else { Instruction.setByte(buf, pc, local); pc += 1; if (bc == _iinc) { int iVal = bc_byte.getByte(); Instruction.setByte(buf, pc, iVal); pc += 1; } } assert(Instruction.opLength(bc) == (pc - curPC)); continue; } // Random bytecode. Just copy it. if (bc >= _bytecode_limit) Utils.log.warning("unrecognized bytescode "+bc +" "+Instruction.byteName(bc)); assert(bc < _bytecode_limit); buf[pc++] = (byte) bc; assert(Instruction.opLength(bc) == (pc - curPC)); continue; } } // now make a permanent copy of the bytecodes code.setBytes(realloc(buf, pc)); code.setInstructionMap(insnMap, numInsns); // fix up labels, now that code has its insnMap Instruction ibr = null; // temporary branch instruction for (int i = 0; i < numLabels; i++) { int curPC = labels[i]; // (Note: Passing ibr in allows reuse, a speed hack.) ibr = Instruction.at(code.bytes, curPC, ibr); if (ibr instanceof Instruction.Switch) { Instruction.Switch isw = (Instruction.Switch) ibr; isw.setDefaultLabel(getLabel(bc_label, code, curPC)); int caseCount = isw.getCaseCount(); for (int j = 0; j < caseCount; j++) { isw.setCaseLabel(j, getLabel(bc_label, code, curPC)); } } else { ibr.setBranchLabel(getLabel(bc_label, code, curPC)); } } if (fixupBuf.size() > 0) { if (verbose > 2) Utils.log.fine("Fixups in code: "+fixupBuf); code.addFixups(fixupBuf); } } } }
⏎ com/sun/java/util/jar/pack/PackageReader.java
Or download all of them as a single archive file:
File name: java.base-11.0.1-src.zip File size: 8740354 bytes Release date: 2018-11-04 Download
2020-05-29, 242238👍, 0💬
Popular Posts:
JDK 1.1 source code directory contains Java source code for JDK 1.1 core classes: "C:\fyicenter\jdk-...
JDK 11 java.security.jgss.jmod is the JMOD file for JDK 11 Security JGSS (Java Generic Security Serv...
JRE 8 rt.jar is the JAR file for JRE 8 RT (Runtime) libraries. JRE (Java Runtime) 8 is the runtime e...
What Is junit-3.8.1.jar? junit-3.8.1.jar is the version 3.8.1 of JUnit JAR library file. JUnit is a ...
JRE 8 rt.jar is the JAR file for JRE 8 RT (Runtime) libraries. JRE (Java Runtime) 8 is the runtime e...