提交 3e2b261e 编写于 作者: K ksrini

7168401: pack200 does not produce a compatible pack file for JDK7 classes if indy is not present

Reviewed-by: jrose
上级 4b2c2953
......@@ -653,8 +653,8 @@ class Attribute implements Comparable<Attribute> {
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);
}
......
......@@ -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<<CLASS_ATTR_ClassFile_version);
}
private void adjustToMajver() throws IOException {
if (getPackageMajver() < JAVA6_PACKAGE_MAJOR_VERSION) {
private void adjustToClassVersion() throws IOException {
if (getHighestClassVersion().lessThan(JAVA6_MAX_CLASS_VERSION)) {
if (verbose > 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) {
......
......@@ -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
......
......@@ -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 {
......
......@@ -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;
......
......@@ -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<Package.Class> classes = new ArrayList<>();
public List<Package.Class> 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<Class.Field> j = c.fields.iterator(); j.hasNext(); ) {
......@@ -1342,4 +1302,75 @@ class Package {
static final List<Class.Field> noFields = Arrays.asList(new Class.Field[0]);
static final List<Class.Method> noMethods = Arrays.asList(new Class.Method[0]);
static final List<InnerClass> 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 ;
}
}
}
......@@ -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.
......
......@@ -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<Integer, int[]> verCounts = new HashMap<>();
Map<Package.Version, int[]> 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
......
/*
* 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();
......
/*
* 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<String, String> {
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));
}
......
......@@ -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<JarEntry> 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)); ) {
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册