/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @author John Rose
*/
class Package {
int verbose;
{
}
int magic;
int package_minver;
int package_majver;
// These fields can be adjusted by driver properties.
// What constants are used in this unit?
Package() {
}
public
void reset() {
}
int getPackageVersion() {
}
// Special empty versions of Code and InnerClasses, used for markers.
static {
}
int getDefaultClassVersion() {
}
/** Return the highest version number of all classes,
* or 0 if there are no classes.
*/
int getHighestClassVersion() {
}
return res;
}
/** Convenience function to choose an archive version based
* on the class file versions observed within the archive.
*/
void choosePackageVersion() {
int classver = getHighestClassVersion();
// There are only old classfiles in this segment or resources
} else {
// Normal case. Use the newest archive format, when available
// TODO: replace the following with JAVA7* when the need arises
}
}
// What Java classes are in this unit?
// Fixed 6211177, converted to throw IOException
if (magic != JAVA_PACKAGE_MAGIC) {
}
if ((package_majver != JAVA6_PACKAGE_MAJOR_VERSION &&
" OR "+
}
}
return classes;
}
public final
// Optional file characteristics and data source (a "class stub")
// File header
int magic;
// Local constant pool (one-way mapping of index => package cp).
// Class header
//int flags; // in Attribute.Holder.this.flags
// Class parts
//ArrayList attributes; // in Attribute.Holder.this.attributes
// Note that InnerClasses may be collected at the package level.
this.magic = JAVA_MAGIC;
this.minver = default_class_minver;
this.majver = default_class_majver;
this.superClass = superClass;
this.interfaces = interfaces;
assert(added);
}
// A blank class; must be read with a ClassReader, etc.
}
return thisClass.stringValue();
}
int getVersion() {
}
}
// Note: equals and hashCode are identity-based.
}
}
// Replace "obvious" SourceFile by null.
return; // no SourceFile attr.
if (minimize) {
// A pair of zero bytes. Cannot use predef. layout.
a = a.addContent(new byte[2]);
} else {
// Expand null attribute to the obvious string.
byte[] bytes = new byte[2];
}
if (minimize) {
// Replace by an all-zero attribute.
} else {
assert(false);
}
}
if (a != olda) {
if (verbose > 2)
}
}
void minimizeSourceFile() {
transformSourceFile(true);
}
void expandSourceFile() {
transformSourceFile(false);
}
return cpMap;
}
}
boolean hasInnerClasses() {
return innerClasses != null;
}
return innerClasses;
}
// Edit the attribute list, if necessary.
removeAttribute(a);
}
/** Given a global map of ICs (keyed by thisClass),
* compute the subset of its Map.values which are
* required to be present in the local InnerClasses
* attribute. Perform this calculation without
* reference to any actual InnerClasses attribute.
* <p>
* The order of the resulting list is consistent
* with that of Package.this.allInnerClasses.
*/
{ // This block temporarily displaces this.innerClasses.
}
// Restrict cpRefs to InnerClasses entries only.
if (!(e instanceof ClassEntry)) continue;
// For every IC reference, add its outers also.
while (e != null) {
e = ic.outerClass;
// If we add A$B$C to the mix, we must also add A$B.
}
}
// This loop is structured this way so as to accumulate
// entries into impliedICs in an order which reflects
// the order of allInnerClasses.
// This one is locally relevant if it describes
// a member of the current class, or if the current
// class uses it somehow. In the particular case
// where thisClass is an inner class, it will already
// be a member of icRefs.
// Add every relevant class to the IC attribute:
if (verbose > 1)
}
}
return impliedICs;
}
// Helper for both minimizing and expanding.
// Computes a symmetric difference.
// Symmetric difference is calculated from I, A like this:
// diff = (I+A) - (I*A)
// Note that the center C is unordered, but the result
// preserves the original ordering of I and A.
//
// Class file rules require that outers precede inners.
// So, add I before A, in case A$B$Z is local, but A$B
// is implicit. The reverse is never the case.
return impliedICs;
// Diff is I since A is empty.
}
if (impliedICs.isEmpty()) {
return actualICs;
// Diff is A since I is empty.
}
// (I*A) is non-trivial
// Diff is now I^A = (I+A)-(I*A).
return impliedICs;
}
/** When packing, anticipate the effect of expandLocalICs.
* Replace the local ICs by their symmetric difference
* with the globally implied ICs for this class; if this
* difference is empty, remove the local ICs altogether.
* <p>
* An empty local IC attribute is reserved to signal
* the unpacker to delete the attribute altogether,
* so a missing local IC attribute signals the unpacker
* to use the globally implied ICs changed.
*/
void minimizeLocalICs() {
// No diff, so transmit no attribute.
// Odd case: No implied ICs, and a zero length attr.
// Do not support it directly.
if (verbose > 0)
}
// No local IC attribute, even though some are implied.
// Signal with trivial attribute.
} else {
// Transmit a non-empty diff, which will create
// a local ICs attribute.
}
// Reduce the set to the symmetric difference.
}
/** When unpacking, undo the effect of minimizeLocalICs.
* Must return negative if any IC tuples may have been deleted.
* Otherwise, return positive if any IC tuples were added.
*/
int expandLocalICs() {
int changed;
// Diff was empty. (Common case.)
if (impliedICs.isEmpty()) {
changed = 0;
} else {
}
// It was a non-empty diff, but the local ICs were absent.
} else {
// Non-trivial diff was transmitted.
actualICs = computeICdiff();
// If we only added more ICs, return +1.
}
return changed;
}
public abstract
this.descriptor = descriptor;
}
return descriptor;
}
}
}
return cpMap;
}
// Careful: The descriptor is used by the package,
// but the classfile breaks it into component refs.
if (mode == VRM_CLASSIC) {
} else {
}
// Handle attribute list:
}
}
}
public
// Order is significant for fields: It is visible to reflection.
int order;
super(flags, descriptor);
assert(!descriptor.isMethod());
assert(added);
}
public byte getLiteralTag() {
return descriptor.getLiteralTag();
}
}
}
public
// Code attribute is specially hardwired.
super(flags, descriptor);
assert(descriptor.isMethod());
assert(added);
}
public void trimToSize() {
super.trimToSize();
code.trimToSize();
}
public int getArgumentSize() {
}
// Sort methods in a canonical order (by type, then by name).
}
}
if (mode == VRM_CLASSIC) {
}
}
}
}
public void trimToSize() {
super.trimToSize();
m.trimToSize();
}
}
if (innerClasses != null) {
}
}
innerClasses = null;
}
}
}
boolean ok = false;
try {
ok = true;
} finally {
if (!ok)
}
}
}
// Handle attribute list:
}
}
// Hook called by ClassReader when it's done.
void finishReading() {
trimToSize();
}
// Build a trivial stub.
}
assert(file.isClassStub());
}
public void maybeChooseFileName() {
return; // do not choose yet
}
}
// The file name is predictable. Transmit "".
return;
}
// If name has not yet been looked up, find it now.
}
}
}
name = canonicalFileName();
}
return getFileName(null);
}
return thisClass.stringValue();
}
}
assert(c.getPackage() == this);
assert(added);
// Make sure the class is represented in the total file order:
}
// What non-class files are in this unit?
return files;
}
}
return classStubs;
}
// caller must fill in contents
}
}
public boolean isDirectory() {
// JAR directory. Useless.
}
public boolean isClassStub() {
}
assert(isClassStub());
return stubClass;
}
public boolean isTrivialClassStub() {
return isClassStub()
}
// The nameString is the key. Ignore other things.
// (Note: The name might be "", in the case of a trivial class stub.)
return false;
}
public int hashCode() {
return nameString.hashCode();
}
// Simple alphabetic sort. PackageWriter uses a better comparator.
}
return nameString+"{"
+"}";
}
return getFileName(null);
}
//if (name.startsWith("./")) name = name.substring(2);
}
}
}
}
public long getFileLength() {
long len = 0;
}
return len;
}
}
}
int nr;
}
}
}
}
}
}
return stub;
}
}
return fname;
}
assert(added);
}
// Is there a globally declared table of inner classes?
public
return allInnerClasses;
}
public
assert(ics != allInnerClasses);
// Make an index:
}
}
/** Return a global inner class record for the given thisClass. */
public
assert(thisClass instanceof ClassEntry);
}
static
final int flags;
// Can name and outerClass be derived from thisClass?
final boolean predictable;
// About 30% of inner classes are anonymous (in rt.jar).
// About 60% are class members; the rest are named locals.
// Nearly all have predictable outers and names.
this.outerClass = outerClass;
this.predictable = computePredictable();
}
private boolean computePredictable() {
//System.out.println("computePredictable "+outerClass+" "+this.name);
//String number = parse[1];
//System.out.println("computePredictable => "+predictable);
return lpredictable;
}
return false;
}
}
public int hashCode() {
}
}
// If the name can be demangled, the package omits
// the products of demangling. Otherwise, include them.
}
}
return thisClass.stringValue();
}
}
// Helper for building InnerClasses attributes.
static private
if (innerClasses == null) {
return; // no attribute; nothing to do
}
if (mode == VRM_CLASSIC) {
}
// Count the entries themselves:
for (InnerClass c : innerClasses) {
}
}
}
//System.out.println("parseInnerClassName "+n);
// parse n = (<pkg>/)*<outer>($<number>)?($<name>)?
// n = (<pkg>/)*<outer>$<number>
} else if ((dollar1
> pkglen
// n = (<pkg>/)*<outer>$<number>$<name>
} else {
// n = (<pkg>/)*<outer>$<name>
}
else
//System.out.println("parseInnerClassName parses "+pkgOuter+" "+number+" "+name);
}
static {
}
for (int i = pos; --i >= 0; ) {
return i;
}
}
return -1;
}
}
return true;
}
for (;;) {
// Work backwards, finding all '$', '#', etc.
if (dollar2 < 0)
break;
if (cutoff == 0)
break;
}
return obvious;
}
/*
static {
assert(getObviousSourceFile("foo").equals("foo.java"));
assert(getObviousSourceFile("foo.bar.baz#1").equals("baz.java"));
}
*/
return ConstantPool.getUtf8Entry(s);
}
return ConstantPool.getLiteralEntry(s);
}
// what is one of { Debug, Compile, Constant, Exceptions, InnerClasses }
if (verbose > 0)
switch (what) {
case "Debug":
strip("SourceFile");
strip("LineNumberTable");
strip("LocalVariableTable");
strip("LocalVariableTypeTable");
break;
case "Compile":
// Keep the inner classes normally.
// Although they have no effect on execution,
// the Reflection API exposes them, and JCK checks them.
// NO: // strip("InnerClasses");
strip("Deprecated");
strip("Synthetic");
break;
case "Exceptions":
// Keep the exceptions normally.
// Although they have no effect on execution,
// the Reflection API exposes them, and JCK checks them.
strip("Exceptions");
break;
case "Constant":
break;
}
}
public void trimToSize() {
c.trimToSize();
}
files.trimToSize();
}
}
}
}
}
public void stripConstantFields() {
// do not strip non-static finals:
if (verbose > 2) {
j.remove();
}
}
}
}
}
}
if (mode != VRM_CLASSIC) {
}
}
}
// Use this before writing the package file.
// It sorts files into a new order which seems likely to
// compress better. It also moves classes to the end of the
// file order. It also removes JAR directory entries, which
// are useless.
@SuppressWarnings("unchecked")
// First reorder the classes, if that is allowed.
if (!keepClassOrder) {
// In one test with rt.jar, this trick gained 0.7%
}
// Remove stubs from resources; maybe we'll add them on at the end,
// if there are some non-trivial ones. The best case is that
// modtimes and options are not transmitted, and the stub files
// for class files do not need to be transmitted at all.
// Also
if (file.isClassStub() ||
i.remove();
}
}
// Sort the remaining non-class files.
// We sort them by file type.
// This keeps files of similar format near each other.
// Put class files at the end, keeping their fixed order.
// Be sure the JAR file's required manifest stays at the front. (4893051)
// Get the file name.
// Extract file basename.
// Extract basename extension.
int r;
// Primary sort key is file extension.
if (r != 0) return r;
return r;
}
});
// Add back the class stubs after sorting, before trimStubs.
}
void trimStubs() {
// Restore enough non-trivial stubs to carry the needed class modtimes.
if (!file.isTrivialClassStub()) {
if (verbose > 1)
break;
}
if (verbose > 2)
i.remove();
}
if (verbose > 0) {
Utils.log.info("Transmitting "+files.size()+" files, including per-file data for "+getClassStubs().size()+" classes out of "+classes.size());
}
}
// Use this before writing the package file.
if (verbose > 1)
if (verbose > 1)
// Work on all entries of a given kind.
}
}
assert(ix.assertIsSorted());
}
}
// Use this before writing the class files.
void ensureAllClassFiles() {
// Add to the end of ths list:
}
}
}