diff --git a/src/share/classes/com/sun/java/util/jar/pack/Attribute.java b/src/share/classes/com/sun/java/util/jar/pack/Attribute.java index 5cf2456bdf1653393949aa75d9fa1e9ec1b0a437..fd644bf759eae8f1266d05232ba225275d27448f 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/Attribute.java +++ b/src/share/classes/com/sun/java/util/jar/pack/Attribute.java @@ -653,8 +653,8 @@ class Attribute implements Comparable { return fixups[0]; // return ref-bearing cookie, if any } - public String layoutForPackageMajver(int majver) { - if (majver <= JAVA5_PACKAGE_MAJOR_VERSION) { + public String layoutForClassVersion(Package.Version vers) { + if (vers.lessThan(JAVA6_MAX_CLASS_VERSION)) { // Disallow layout syntax in the oldest protocol version. return expandCaseDashNotation(layout); } diff --git a/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java b/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java index a63491b9a34cfe04b01ab877ff9822cd68a1fd96..f3d5cec8e48d9baf12c4200ef31a989f134426b3 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java +++ b/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java @@ -74,30 +74,27 @@ class BandStructure { abstract protected Index getCPIndex(byte tag); - // Local copy of package version. - private int packageMajver = -1; + // Local copy of highest class version. + private Package.Version highestClassVersion = null; /** Call this exactly once, early, to specify the archive major version. */ - public void initPackageMajver(int packageMajver) throws IOException { - assert(packageMajver > 0 && packageMajver < 0x10000); - if (this.packageMajver > 0) { + public void initHighestClassVersion(Package.Version highestClassVersion) throws IOException { + if (this.highestClassVersion != null) { throw new IOException( - "Package majver is already initialized to " + this.packageMajver+ - "; new setting is " + packageMajver); + "Highest class major version is already initialized to " + + this.highestClassVersion + "; new setting is " + highestClassVersion); } - this.packageMajver = packageMajver; - adjustToMajver(); + this.highestClassVersion = highestClassVersion; + adjustToClassVersion(); } - public int getPackageMajver() { - if (packageMajver < 0) { - throw new RuntimeException("Package majver not yet initialized"); - } - return packageMajver; + + public Package.Version getHighestClassVersion() { + return highestClassVersion; } private final boolean isReader = this instanceof PackageReader; - protected BandStructure() { - } + + protected BandStructure() {} final static Coding BYTE1 = Coding.of(1,256); @@ -1866,20 +1863,12 @@ class BandStructure { attrClassFileVersionMask = (1< 0) Utils.log.fine("Legacy package version"); // Revoke definition of pre-1.6 attribute type. undefineAttribute(CODE_ATTR_StackMapTable, ATTR_CONTEXT_CODE); } - if (getPackageMajver() < JAVA7_PACKAGE_MAJOR_VERSION) { - if (testBit(archiveOptions, AO_HAVE_CP_EXTRAS)) - // this bit was reserved for future use in previous versions - throw new IOException("Format bits for Java 7 must be zero in previous releases"); - } - if (testBit(archiveOptions, AO_UNUSED_MBZ)) { - throw new IOException("High archive option bits are reserved and must be zero: "+Integer.toHexString(archiveOptions)); - } } protected void initAttrIndexLimit() { @@ -1942,21 +1931,14 @@ class BandStructure { } } - protected Attribute makeClassFileVersionAttr(int minver, int majver) { - byte[] bytes = { - (byte)(minver >> 8), (byte)minver, - (byte)(majver >> 8), (byte)majver - }; - return attrClassFileVersion.addContent(bytes); + protected Attribute makeClassFileVersionAttr(Package.Version ver) { + return attrClassFileVersion.addContent(ver.asBytes()); } - protected short[] parseClassFileVersionAttr(Attribute attr) { + protected Package.Version parseClassFileVersionAttr(Attribute attr) { assert(attr.layout() == attrClassFileVersion); assert(attr.size() == 4); - byte[] bytes = attr.bytes(); - int minver = ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF); - int majver = ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF); - return new short[]{ (short) minver, (short) majver }; + return Package.Version.of(attr.bytes()); } private boolean assertBandOKForElems(Band[] ab, Attribute.Layout.Element[] elems) { diff --git a/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java b/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java index 545faab9127347c75a37d6c8f4500d34612d7a7a..2ca2d0926c64fa156dedfaf17ada7073f5e506e0 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java +++ b/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java @@ -174,27 +174,31 @@ class ClassReader { ("Bad magic number in class file " +Integer.toHexString(cls.magic), ATTR_CONTEXT_CLASS, "magic-number", "pass"); - cls.minver = (short) readUnsignedShort(); - cls.majver = (short) readUnsignedShort(); + int minver = (short) readUnsignedShort(); + int majver = (short) readUnsignedShort(); + cls.version = Package.Version.of(majver, minver); + //System.out.println("ClassFile.version="+cls.majver+"."+cls.minver); - String bad = checkVersion(cls.majver, cls.minver); + String bad = checkVersion(cls.version); if (bad != null) { throw new Attribute.FormatException ("classfile version too "+bad+": " - +cls.majver+"."+cls.minver+" in "+cls.file, + +cls.version+" in "+cls.file, ATTR_CONTEXT_CLASS, "version", "pass"); } } - private String checkVersion(int majver, int minver) { - if (majver < pkg.min_class_majver || - (majver == pkg.min_class_majver && - minver < pkg.min_class_minver)) { + private String checkVersion(Package.Version ver) { + int majver = ver.major; + int minver = ver.minor; + if (majver < pkg.minClassVersion.major || + (majver == pkg.minClassVersion.major && + minver < pkg.minClassVersion.minor)) { return "small"; } - if (majver > pkg.max_class_majver || - (majver == pkg.max_class_majver && - minver > pkg.max_class_minver)) { + if (majver > pkg.maxClassVersion.major || + (majver == pkg.maxClassVersion.major && + minver > pkg.maxClassVersion.minor)) { return "large"; } return null; // OK diff --git a/src/share/classes/com/sun/java/util/jar/pack/ClassWriter.java b/src/share/classes/com/sun/java/util/jar/pack/ClassWriter.java index dacae44b4d36f12506e1134a8d81a1e47babecda..deb66252a23c9bd22e3940f9f68fa21196927c60 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/ClassWriter.java +++ b/src/share/classes/com/sun/java/util/jar/pack/ClassWriter.java @@ -113,8 +113,8 @@ class ClassWriter { void writeMagicNumbers() throws IOException { writeInt(cls.magic); - writeShort(cls.minver); - writeShort(cls.majver); + writeShort(cls.version.minor); + writeShort(cls.version.major); } void writeConstantPool() throws IOException { diff --git a/src/share/classes/com/sun/java/util/jar/pack/Constants.java b/src/share/classes/com/sun/java/util/jar/pack/Constants.java index c7fa00e0f18bb8af5b1f433b3b171f3756ef161e..c4c3a8f3abb0f701dfaa344c01bd90c8475fdc21 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/Constants.java +++ b/src/share/classes/com/sun/java/util/jar/pack/Constants.java @@ -43,30 +43,40 @@ class Constants { 1.0 to 1.3.X 45,3 1.4 to 1.4.X 46,0 1.5 to 1.5.X 49,0 - 1.6 to 1.5.x 50,0 NOTE Assumed for now + 1.6 to 1.5.x 50,0 + 1.7 to 1.6.x 51,0 */ - public final static short JAVA_MIN_CLASS_MAJOR_VERSION = 45; - public final static short JAVA_MIN_CLASS_MINOR_VERSION = 03; + public final static Package.Version JAVA_MIN_CLASS_VERSION = + Package.Version.of(45, 03); - public final static short JAVA5_MAX_CLASS_MAJOR_VERSION = 49; - public final static short JAVA5_MAX_CLASS_MINOR_VERSION = 0; + public final static Package.Version JAVA5_MAX_CLASS_VERSION = + Package.Version.of(49, 00); - public final static short JAVA6_MAX_CLASS_MAJOR_VERSION = 50; - public final static short JAVA6_MAX_CLASS_MINOR_VERSION = 0; + public final static Package.Version JAVA6_MAX_CLASS_VERSION = + Package.Version.of(50, 00); - public final static short JAVA7_MAX_CLASS_MAJOR_VERSION = 51; - public final static short JAVA7_MAX_CLASS_MINOR_VERSION = 0; + public final static Package.Version JAVA7_MAX_CLASS_VERSION = + Package.Version.of(51, 00); public final static int JAVA_PACKAGE_MAGIC = 0xCAFED00D; - public final static int JAVA5_PACKAGE_MAJOR_VERSION = 150; - public final static int JAVA5_PACKAGE_MINOR_VERSION = 7; - public final static int JAVA6_PACKAGE_MAJOR_VERSION = 160; - public final static int JAVA6_PACKAGE_MINOR_VERSION = 1; + public final static Package.Version JAVA5_PACKAGE_VERSION = + Package.Version.of(150, 7); - public final static int JAVA7_PACKAGE_MAJOR_VERSION = 170; - public final static int JAVA7_PACKAGE_MINOR_VERSION = 1; + public final static Package.Version JAVA6_PACKAGE_VERSION = + Package.Version.of(160, 1); + + public final static Package.Version JAVA7_PACKAGE_VERSION = + Package.Version.of(170, 1); + + // upper limit, should point to the latest class version + public final static Package.Version JAVA_MAX_CLASS_VERSION = + JAVA7_MAX_CLASS_VERSION; + + // upper limit should point to the latest package version, for version info!. + public final static Package.Version MAX_PACKAGE_VERSION = + JAVA7_PACKAGE_VERSION; public final static int CONSTANT_POOL_INDEX_LIMIT = 0x10000; public final static int CONSTANT_POOL_NARROW_LIMIT = 0x00100; diff --git a/src/share/classes/com/sun/java/util/jar/pack/Package.java b/src/share/classes/com/sun/java/util/jar/pack/Package.java index fee97f4d9642c2b52e6e107e8215185f0972d255..64f9db5c3098c957bc981fd8e91c48e80432ddeb 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/Package.java +++ b/src/share/classes/com/sun/java/util/jar/pack/Package.java @@ -25,6 +25,7 @@ package com.sun.java.util.jar.pack; +import java.util.jar.Pack200; import com.sun.java.util.jar.pack.Attribute.Layout; import com.sun.java.util.jar.pack.ConstantPool.ClassEntry; import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry; @@ -67,46 +68,58 @@ class Package { verbose = pmap.getInteger(Utils.DEBUG_VERBOSE); } - int magic; - int package_minver; - int package_majver; + final int magic = JAVA_PACKAGE_MAGIC; int default_modtime = NO_MODTIME; int default_options = 0; // FO_DEFLATE_HINT - short default_class_majver = -1; // fill in later - short default_class_minver = 0; // fill in later + Version defaultClassVersion = null; // These fields can be adjusted by driver properties. - short min_class_majver = JAVA_MIN_CLASS_MAJOR_VERSION; - short min_class_minver = JAVA_MIN_CLASS_MINOR_VERSION; - short max_class_majver = JAVA7_MAX_CLASS_MAJOR_VERSION; - short max_class_minver = JAVA7_MAX_CLASS_MINOR_VERSION; + final Version minClassVersion; + final Version maxClassVersion; + // null, indicates that consensus rules during package write + final Version packageVersion; + + Version observedHighestClassVersion = null; - short observed_max_class_majver = min_class_majver; - short observed_max_class_minver = min_class_minver; // What constants are used in this unit? ConstantPool.IndexGroup cp = new ConstantPool.IndexGroup(); - Package() { - magic = JAVA_PACKAGE_MAGIC; - package_minver = -1; // fill in later - package_majver = 0; // fill in later + /* + * typically used by the PackageReader to set the defaults, in which + * case we take the defaults. + */ + public Package() { + minClassVersion = JAVA_MIN_CLASS_VERSION; + maxClassVersion = JAVA_MAX_CLASS_VERSION; + packageVersion = null; } - public - void reset() { + + /* + * Typically used by the PackerImpl during before packing, the defaults are + * overridden by the users preferences. + */ + public Package(Version minClassVersion, Version maxClassVersion, Version packageVersion) { + // Fill in permitted range of major/minor version numbers. + this.minClassVersion = minClassVersion == null + ? JAVA_MIN_CLASS_VERSION + : minClassVersion; + this.maxClassVersion = maxClassVersion == null + ? JAVA_MAX_CLASS_VERSION + : maxClassVersion; + this.packageVersion = packageVersion; + } + + + public void reset() { cp = new ConstantPool.IndexGroup(); classes.clear(); files.clear(); BandStructure.nextSeqForDebug = 0; - package_minver = -1; // fill in later - package_majver = 0; // fill in later - } - - int getPackageVersion() { - return (package_majver << 16) + package_minver; + observedHighestClassVersion = null; } // Special empty versions of Code and InnerClasses, used for markers. @@ -128,73 +141,31 @@ class Package { attrDefs = Collections.unmodifiableMap(ad); } - int getDefaultClassVersion() { - return (default_class_majver << 16) + (char)default_class_minver; + Version getDefaultClassVersion() { + return defaultClassVersion; } /** Return the highest version number of all classes, * or 0 if there are no classes. */ - int getHighestClassVersion() { - int res = 0; // initial low value + private void setHighestClassVersion() { + if (observedHighestClassVersion != null) + return; + Version res = JAVA_MIN_CLASS_VERSION; // initial low value for (Class cls : classes) { - int ver = cls.getVersion(); - if (res < ver) res = ver; + Version ver = cls.getVersion(); + if (res.lessThan(ver)) res = ver; } - return res; + observedHighestClassVersion = res; } - /** Convenience function to choose an archive version based - * on the class file versions observed within the archive. - */ - void choosePackageVersion() { - assert(package_majver <= 0); // do not call this twice - int classver = getHighestClassVersion(); - if (classver == 0 || (classver >>> 16) < JAVA6_MAX_CLASS_MAJOR_VERSION) { - // There are only old classfiles in this segment or resources - package_majver = JAVA5_PACKAGE_MAJOR_VERSION; - package_minver = JAVA5_PACKAGE_MINOR_VERSION; - } else if ((classver >>> 16) == JAVA6_MAX_CLASS_MAJOR_VERSION) { - package_majver = JAVA6_PACKAGE_MAJOR_VERSION; - package_minver = JAVA6_PACKAGE_MINOR_VERSION; - } else { - // Normal case. Use the newest archive format, when available - package_majver = JAVA7_PACKAGE_MAJOR_VERSION; - package_minver = JAVA7_PACKAGE_MINOR_VERSION; - } + Version getHighestClassVersion() { + setHighestClassVersion(); + return observedHighestClassVersion; } // What Java classes are in this unit? - // Fixed 6211177, converted to throw IOException - void checkVersion() throws IOException { - if (magic != JAVA_PACKAGE_MAGIC) { - String gotMag = Integer.toHexString(magic); - String expMag = Integer.toHexString(JAVA_PACKAGE_MAGIC); - throw new IOException("Unexpected package magic number: got "+gotMag+"; expected "+expMag); - } - int[] majminFound = null; - for (int[] majmin : new int[][]{ - { JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION }, - { JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION }, - { JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION } - }) { - if (package_majver == majmin[0] && package_minver == majmin[1]) { - majminFound = majmin; - break; - } - } - if (majminFound == null) { - String gotVer = package_majver+"."+package_minver; - String expVer = JAVA7_PACKAGE_MAJOR_VERSION+"."+JAVA7_PACKAGE_MINOR_VERSION+ - " OR "+ - JAVA6_PACKAGE_MAJOR_VERSION+"."+JAVA6_PACKAGE_MINOR_VERSION+ - " OR "+ - JAVA5_PACKAGE_MAJOR_VERSION+"."+JAVA5_PACKAGE_MINOR_VERSION; - throw new IOException("Unexpected package minor version: got "+gotVer+"; expected "+expVer); - } - } - ArrayList classes = new ArrayList<>(); public List getClasses() { @@ -210,7 +181,7 @@ class Package { // File header int magic; - short minver, majver; + Version version; // Local constant pool (one-way mapping of index => package cp). Entry[] cpMap; @@ -231,8 +202,7 @@ class Package { Class(int flags, ClassEntry thisClass, ClassEntry superClass, ClassEntry[] interfaces) { this.magic = JAVA_MAGIC; - this.minver = default_class_minver; - this.majver = default_class_majver; + this.version = defaultClassVersion; this.flags = flags; this.thisClass = thisClass; this.superClass = superClass; @@ -254,11 +224,8 @@ class Package { return thisClass.stringValue(); } - int getVersion() { - return (majver << 16) + (char)minver; - } - String getVersionString() { - return versionStringOf(majver, minver); + Version getVersion() { + return this.version; } // Note: equals and hashCode are identity-based. @@ -1182,13 +1149,6 @@ class Package { } } - public static String versionStringOf(int majver, int minver) { - return majver+"."+minver; - } - public static String versionStringOf(int version) { - return versionStringOf(version >>> 16, (char)version); - } - public void stripConstantFields() { for (Class c : classes) { for (Iterator j = c.fields.iterator(); j.hasNext(); ) { @@ -1342,4 +1302,75 @@ class Package { static final List noFields = Arrays.asList(new Class.Field[0]); static final List noMethods = Arrays.asList(new Class.Method[0]); static final List noInnerClasses = Arrays.asList(new InnerClass[0]); + + protected static final class Version { + + public final short major; + public final short minor; + + private Version(short major, short minor) { + this.major = major; + this.minor = minor; + } + + public String toString() { + return major + "." + minor; + } + + public boolean equals(Object that) { + return that instanceof Version + && major == ((Version)that).major + && minor == ((Version)that).minor; + } + + public int intValue() { + return (major << 16) + minor; + } + + public int hashCode() { + return (major << 16) + 7 + minor; + } + + public static Version of(int major, int minor) { + return new Version((short)major, (short)minor); + } + + public static Version of(byte[] bytes) { + int minor = ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF); + int major = ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF); + return new Version((short)major, (short)minor); + } + + public static Version of(int major_minor) { + short minor = (short)major_minor; + short major = (short)(major_minor >>> 16); + return new Version(major, minor); + } + + public static Version makeVersion(PropMap props, String partialKey) { + int min = props.getInteger(Utils.COM_PREFIX + + partialKey + ".minver", -1); + int maj = props.getInteger(Utils.COM_PREFIX + + partialKey + ".majver", -1); + return min >= 0 && maj >= 0 ? Version.of(maj, min) : null; + } + public byte[] asBytes() { + byte[] bytes = { + (byte) (minor >> 8), (byte) minor, + (byte) (major >> 8), (byte) major + }; + return bytes; + } + public int compareTo(Version that) { + return this.intValue() - that.intValue(); + } + + public boolean lessThan(Version that) { + return compareTo(that) < 0 ; + } + + public boolean greaterThan(Version that) { + return compareTo(that) > 0 ; + } + } } diff --git a/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java b/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java index 8813b5e3f253cc80ee3886d556800620931e0320..26bade85c5d1571ba4d039fcf66ac49308871b26 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java +++ b/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java @@ -60,6 +60,7 @@ class PackageReader extends BandStructure { Package pkg; byte[] bytes; LimitedBuffer in; + Package.Version packageVersion; PackageReader(Package pkg, InputStream in) throws IOException { this.pkg = pkg; @@ -220,7 +221,6 @@ class PackageReader extends BandStructure { final static int MAGIC_BYTES = 4; void readArchiveMagic() throws IOException { - // Read a minimum of bytes in the first gulp. in.setReadLimit(MAGIC_BYTES + AH_LENGTH_MIN); @@ -230,10 +230,38 @@ class PackageReader extends BandStructure { archive_magic.readFrom(in); // read and check magic numbers: - pkg.magic = getMagicInt32(); + 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[] { + JAVA7_PACKAGE_VERSION, + JAVA6_PACKAGE_VERSION, + JAVA5_PACKAGE_VERSION + }) { + if (packageVersion.equals(v)) { + versionFound = v; + break; + } + } + if (versionFound == null) { + String expVer = 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] @@ -264,10 +292,11 @@ class PackageReader extends BandStructure { archive_header_0.expectLength(AH_LENGTH_0); archive_header_0.readFrom(in); - pkg.package_minver = archive_header_0.getInt(); - pkg.package_majver = archive_header_0.getInt(); - pkg.checkVersion(); - this.initPackageMajver(pkg.package_majver); + 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(); @@ -324,8 +353,9 @@ class PackageReader extends BandStructure { numInnerClasses = archive_header_1.getInt(); - pkg.default_class_minver = (short) archive_header_1.getInt(); - pkg.default_class_majver = (short) 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(); @@ -414,7 +444,7 @@ class PackageReader extends BandStructure { } void checkLegacy(String bandname) { - if (this.pkg.package_majver < JAVA7_PACKAGE_MAJOR_VERSION) { + if (packageVersion.lessThan(JAVA7_PACKAGE_VERSION)) { throw new RuntimeException("unexpected band " + bandname); } } @@ -947,9 +977,9 @@ class PackageReader extends BandStructure { name.stringValue(), layout.stringValue()); // Check layout string for Java 6 extensions. - String pvLayout = def.layoutForPackageMajver(getPackageMajver()); + String pvLayout = def.layoutForClassVersion(getHighestClassVersion()); if (!pvLayout.equals(def.layout())) { - throw new IOException("Bad attribute layout in version 150 archive: "+def.layout()); + throw new IOException("Bad attribute layout in archive: "+def.layout()); } this.setAttributeLayoutIndex(def, index); if (dump != null) dump.println(index+" "+def); @@ -1140,12 +1170,9 @@ class PackageReader extends BandStructure { Attribute retroVersion = cls.getAttribute(attrClassFileVersion); if (retroVersion != null) { cls.removeAttribute(retroVersion); - short[] minmajver = parseClassFileVersionAttr(retroVersion); - cls.minver = minmajver[0]; - cls.majver = minmajver[1]; + cls.version = parseClassFileVersionAttr(retroVersion); } else { - cls.minver = pkg.default_class_minver; - cls.majver = pkg.default_class_majver; + cls.version = pkg.defaultClassVersion; } // Replace null SourceFile by "obvious" string. diff --git a/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java b/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java index d40a6d3889ee67cea3343b77adc65d08c2dcb567..a4a298261359c5592b3d3268b298be95b8cc6e25 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java +++ b/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java @@ -49,12 +49,13 @@ import static com.sun.java.util.jar.pack.Constants.*; class PackageWriter extends BandStructure { Package pkg; OutputStream finalOut; + Package.Version packageVersion; PackageWriter(Package pkg, OutputStream out) throws IOException { this.pkg = pkg; this.finalOut = out; - // Caller has specified archive version in the package: - initPackageMajver(pkg.package_majver); + // Caller has specified maximum class file version in the package: + initHighestClassVersion(pkg.getHighestClassVersion()); } void write() throws IOException { @@ -118,6 +119,57 @@ class PackageWriter extends BandStructure { collectInnerClasses(); } + /* + * Convenience function to choose an archive version based + * on the class file versions observed within the archive + * or set the user defined version preset via properties. + */ + void chooseDefaultPackageVersion() throws IOException { + if (pkg.packageVersion != null) { + packageVersion = pkg.packageVersion; + if (verbose > 0) { + Utils.log.info("package version overridden with: " + + packageVersion); + } + return; + } + + Package.Version highV = getHighestClassVersion(); + // set the package version now + if (highV.lessThan(JAVA6_MAX_CLASS_VERSION)) { + // There are only old classfiles in this segment or resources + packageVersion = JAVA5_PACKAGE_VERSION; + } else if (highV.equals(JAVA6_MAX_CLASS_VERSION) || + (highV.equals(JAVA7_MAX_CLASS_VERSION) && !pkg.cp.haveExtraTags())) { + // force down the package version if we have jdk7 classes without + // any Indy references, this is because jdk7 class file (52.0) without + // Indy is identical to jdk6 class file (51.0). + packageVersion = JAVA6_PACKAGE_VERSION; + } else { + // Normal case. Use the newest archive format, when available + packageVersion = JAVA7_PACKAGE_VERSION; + } + + if (verbose > 0) { + Utils.log.info("Highest version class file: " + highV + + " package version: " + packageVersion); + } + } + + void checkVersion() throws IOException { + assert(packageVersion != null); + + if (packageVersion.lessThan(JAVA7_PACKAGE_VERSION)) { + // this bit was reserved for future use in previous versions + if (testBit(archiveOptions, AO_HAVE_CP_EXTRAS)) { + throw new IOException("Format bits for Java 7 must be zero in previous releases"); + } + } + if (testBit(archiveOptions, AO_UNUSED_MBZ)) { + throw new IOException("High archive option bits are reserved and must be zero: " + Integer.toHexString(archiveOptions)); + } + } + void setArchiveOptions() { // Decide on some archive options early. // Does not decide on: AO_HAVE_SPECIAL_FORMATS, @@ -168,11 +220,11 @@ class PackageWriter extends BandStructure { } } // Decide on default version number (majority rule). - Map verCounts = new HashMap<>(); + Map verCounts = new HashMap<>(); int bestCount = 0; - int bestVersion = -1; + Package.Version bestVersion = null; for (Class cls : pkg.classes) { - int version = cls.getVersion(); + Package.Version version = cls.getVersion(); int[] var = verCounts.get(version); if (var == null) { var = new int[1]; @@ -186,28 +238,22 @@ class PackageWriter extends BandStructure { } } verCounts.clear(); - if (bestVersion == -1) bestVersion = 0; // degenerate case - int bestMajver = (char)(bestVersion >>> 16); - int bestMinver = (char)(bestVersion); - pkg.default_class_majver = (short) bestMajver; - pkg.default_class_minver = (short) bestMinver; - String bestVerStr = Package.versionStringOf(bestMajver, bestMinver); + if (bestVersion == null) bestVersion = JAVA_MIN_CLASS_VERSION; // degenerate case + pkg.defaultClassVersion = bestVersion; if (verbose > 0) - Utils.log.info("Consensus version number in segment is "+bestVerStr); + Utils.log.info("Consensus version number in segment is " + bestVersion); if (verbose > 0) - Utils.log.info("Highest version number in segment is "+ - Package.versionStringOf(pkg.getHighestClassVersion())); + Utils.log.info("Highest version number in segment is " + + pkg.getHighestClassVersion()); // Now add explicit pseudo-attrs. to classes with odd versions. for (Class cls : pkg.classes) { - if (cls.getVersion() != bestVersion) { - Attribute a = makeClassFileVersionAttr(cls.minver, cls.majver); + if (!cls.getVersion().equals(bestVersion)) { + Attribute a = makeClassFileVersionAttr(cls.getVersion()); if (verbose > 1) { - String clsVer = cls.getVersionString(); - String pkgVer = bestVerStr; - Utils.log.fine("Version "+clsVer+" of "+cls - +" doesn't match package version " - +pkgVer); + Utils.log.fine("Version "+cls.getVersion() + " of " + cls + + " doesn't match package version " + + bestVersion); } // Note: Does not add in "natural" order. (Who cares?) cls.addAttribute(a); @@ -252,7 +298,7 @@ class PackageWriter extends BandStructure { } void writeFileHeader() throws IOException { - pkg.checkVersion(); + chooseDefaultPackageVersion(); writeArchiveMagic(); writeArchiveHeader(); } @@ -322,12 +368,13 @@ class PackageWriter extends BandStructure { if (haveCPExtra) headerSizeForDebug += AH_CP_EXTRA_LEN; - assert(pkg.package_majver > 0); // caller must specify! - archive_header_0.putInt(pkg.package_minver); - archive_header_0.putInt(pkg.package_majver); + // the archiveOptions are all initialized, sanity check now!. + checkVersion(); + + archive_header_0.putInt(packageVersion.minor); + archive_header_0.putInt(packageVersion.major); if (verbose > 0) - Utils.log.info("Package Version for this segment:"+ - Package.versionStringOf(pkg.getPackageVersion())); + Utils.log.info("Package Version for this segment:" + packageVersion); archive_header_0.putInt(archiveOptions); // controls header format assert(archive_header_0.length() == AH_LENGTH_0); @@ -361,8 +408,8 @@ class PackageWriter extends BandStructure { writeConstantPoolCounts(haveNumbers, haveCPExtra); archive_header_1.putInt(pkg.getAllInnerClasses().size()); - archive_header_1.putInt(pkg.default_class_minver); - archive_header_1.putInt(pkg.default_class_majver); + archive_header_1.putInt(pkg.defaultClassVersion.minor); + archive_header_1.putInt(pkg.defaultClassVersion.major); archive_header_1.putInt(pkg.classes.size()); // Sanity: Make sure we came out to 29 (less optional fields): @@ -892,7 +939,7 @@ class PackageWriter extends BandStructure { if (predefIndex == null) { // Make sure the package CP can name the local attribute. Entry ne = ConstantPool.getUtf8Entry(def.name()); - String layout = def.layoutForPackageMajver(getPackageMajver()); + String layout = def.layoutForClassVersion(getHighestClassVersion()); Entry le = ConstantPool.getUtf8Entry(layout); requiredEntries.add(ne); requiredEntries.add(le); @@ -988,7 +1035,7 @@ class PackageWriter extends BandStructure { assert((header & ADH_CONTEXT_MASK) == def.ctype()); attr_definition_headers.putByte(header); attr_definition_name.putRef(ConstantPool.getUtf8Entry(def.name())); - String layout = def.layoutForPackageMajver(getPackageMajver()); + String layout = def.layoutForClassVersion(getHighestClassVersion()); attr_definition_layout.putRef(ConstantPool.getUtf8Entry(layout)); // Check that we are transmitting that correct attribute index: boolean debug = false; @@ -1542,8 +1589,8 @@ class PackageWriter extends BandStructure { break; default: // CONSTANT_MethodHandle, etc. - if (getPackageMajver() < JAVA7_PACKAGE_MAJOR_VERSION) { - throw new IOException("bad package major version for Java 7 ldc"); + if (getHighestClassVersion().lessThan(JAVA7_MAX_CLASS_VERSION)) { + throw new IOException("bad class file major version for Java 7 ldc"); } bc_which = bc_loadablevalueref; switch (bc) { @@ -1581,8 +1628,8 @@ class PackageWriter extends BandStructure { // Make sure the discarded bytes are sane: assert(i.getConstant() == (1+((MemberEntry)ref).descRef.typeRef.computeSize(true)) << 8); } else if (bc == _invokedynamic) { - if (getPackageMajver() < JAVA7_PACKAGE_MAJOR_VERSION) { - throw new IOException("bad package major version for Java 7 invokedynamic"); + if (getHighestClassVersion().lessThan(JAVA7_MAX_CLASS_VERSION)) { + throw new IOException("bad class major version for Java 7 invokedynamic"); } assert(i.getLength() == 5); assert(i.getConstant() == 0); // last 2 bytes MBZ diff --git a/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java b/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java index 93b743bcdc750527e1f0d6a02d511cc62f1aa80c..c7ef4ee20136973c4fe4cf9b8fadd3f57f54b094 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java +++ b/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -164,8 +164,11 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { if (verbose > 0) Utils.log.info(props.toString()); } - // Here's where the bits are collected before getting packed: - final Package pkg = new Package(); + // Here's where the bits are collected before getting packed, we also + // initialize the version numbers now. + final Package pkg = new Package(Package.Version.makeVersion(props, "min.class"), + Package.Version.makeVersion(props, "max.class"), + Package.Version.makeVersion(props, "package")); final String unknownAttrCommand; { @@ -279,23 +282,6 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { if (verbose > 0) Utils.log.info("passFiles = " + passFiles); } - { - // Fill in permitted range of major/minor version numbers. - int ver; - if ((ver = props.getInteger(Utils.COM_PREFIX+"min.class.majver")) != 0) - pkg.min_class_majver = (short) ver; - if ((ver = props.getInteger(Utils.COM_PREFIX+"min.class.minver")) != 0) - pkg.min_class_minver = (short) ver; - if ((ver = props.getInteger(Utils.COM_PREFIX+"max.class.majver")) != 0) - pkg.max_class_majver = (short) ver; - if ((ver = props.getInteger(Utils.COM_PREFIX+"max.class.minver")) != 0) - pkg.max_class_minver = (short) ver; - if ((ver = props.getInteger(Utils.COM_PREFIX+"package.minver")) != 0) - pkg.package_minver = (short) ver; - if ((ver = props.getInteger(Utils.COM_PREFIX+"package.majver")) != 0) - pkg.package_majver = (short) ver; - } - { // Hook for testing: Forces use of special archive modes. int opt = props.getInteger(Utils.COM_PREFIX+"archive.options"); @@ -603,9 +589,6 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { if (props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions"); if (props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses"); - // Must choose an archive version; PackageWriter does not. - if (pkg.package_majver <= 0) pkg.choosePackageVersion(); - PackageWriter pw = new PackageWriter(pkg, out); pw.archiveNextCount = nextCount; pw.write(); diff --git a/src/share/classes/com/sun/java/util/jar/pack/PropMap.java b/src/share/classes/com/sun/java/util/jar/pack/PropMap.java index 07887b9c55b39a960d812138478eb8f4fb19d85a..e1a385546c96e91ecee0a2bbe655704b12d3a8e5 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/PropMap.java +++ b/src/share/classes/com/sun/java/util/jar/pack/PropMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -193,13 +193,18 @@ final class PropMap implements SortedMap { boolean setBoolean(String s, boolean val) { return toBoolean(setProperty(s, String.valueOf(val))); } - int toInteger(String val) { - if (val == null) return 0; + return toInteger(val, 0); + } + int toInteger(String val, int def) { + if (val == null) return def; if (Pack200.Packer.TRUE.equals(val)) return 1; if (Pack200.Packer.FALSE.equals(val)) return 0; return Integer.parseInt(val); } + int getInteger(String s, int def) { + return toInteger(getProperty(s), def); + } int getInteger(String s) { return toInteger(getProperty(s)); } diff --git a/src/share/classes/com/sun/java/util/jar/pack/Utils.java b/src/share/classes/com/sun/java/util/jar/pack/Utils.java index 06ecaef5bbfd10c06b31184f9eb876adb131b06b..5edd73e21cb1cad39250883e6e0e689e851272e5 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/Utils.java +++ b/src/share/classes/com/sun/java/util/jar/pack/Utils.java @@ -25,12 +25,6 @@ package com.sun.java.util.jar.pack; -import com.sun.java.util.jar.pack.ConstantPool.ClassEntry; -import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry; -import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry; -import com.sun.java.util.jar.pack.ConstantPool.MemberEntry; -import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; -import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -38,9 +32,8 @@ import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Collections; import java.util.Date; -import java.util.Enumeration; -import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; @@ -211,9 +204,7 @@ class Utils { static String getVersionString() { return "Pack200, Vendor: " + System.getProperty("java.vendor") + - ", Version: " + - Constants.JAVA6_PACKAGE_MAJOR_VERSION + "." + - Constants.JAVA6_PACKAGE_MINOR_VERSION; + ", Version: " + Constants.MAX_PACKAGE_VERSION; } static void markJarFile(JarOutputStream out) throws IOException { @@ -240,8 +231,7 @@ class Utils { } static void copyJarFile(JarFile in, JarOutputStream out) throws IOException { byte[] buffer = new byte[1 << 14]; - for (Enumeration e = in.entries(); e.hasMoreElements(); ) { - JarEntry je = e.nextElement(); + for (JarEntry je : Collections.list(in.entries())) { out.putNextEntry(je); InputStream ein = in.getInputStream(je); for (int nr; 0 < (nr = ein.read(buffer)); ) { diff --git a/test/tools/pack200/PackageVersionTest.java b/test/tools/pack200/PackageVersionTest.java index 8569781a6ec26ce3e7399d9522483727dfb0cde9..fe6d5d9cb596d8a7040ae29300d3afb77934721e 100644 --- a/test/tools/pack200/PackageVersionTest.java +++ b/test/tools/pack200/PackageVersionTest.java @@ -24,7 +24,7 @@ /* * @test - * @bug 6712743 6991164 + * @bug 6712743 6991164 7168401 * @summary verify package versions * @compile -XDignore.symbol.file Utils.java PackageVersionTest.java * @run main PackageVersionTest @@ -71,8 +71,9 @@ public class PackageVersionTest { verifyPack("Test6.class", JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION); - verifyPack("Test7.class", JAVA7_PACKAGE_MAJOR_VERSION, - JAVA7_PACKAGE_MINOR_VERSION); + // a jar file devoid of indy classes must generate 160.1 package file + verifyPack("Test7.class", JAVA6_PACKAGE_MAJOR_VERSION, + JAVA6_PACKAGE_MINOR_VERSION); // test for resource file, ie. no class files verifyPack("Test6.java", JAVA5_PACKAGE_MAJOR_VERSION, @@ -84,7 +85,7 @@ public class PackageVersionTest { String versionStr = unpacker.toString(); String expected = "Pack200, Vendor: " + System.getProperty("java.vendor") + ", Version: " + - JAVA6_PACKAGE_MAJOR_VERSION + "." + JAVA6_PACKAGE_MINOR_VERSION; + JAVA7_PACKAGE_MAJOR_VERSION + "." + JAVA7_PACKAGE_MINOR_VERSION; if (!versionStr.equals(expected)) { System.out.println("Expected: " + expected); System.out.println("Obtained: " + versionStr);