# HG changeset patch # User miroslawzn # Date 1354324090 28800 # Node ID f3f9b711bb1228f4598ded7eb0380c32eba63521 # Parent 9bbc6817b00c3e9d4eba05d53a8a20b45947ea03 7186945: Unpack200 improvement 7186957: Improve Pack200 data validation 7186946: Refine unpacker resource usage Reviewed-by: ksrini 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 --- jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java +++ jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -22,7 +22,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package com.sun.java.util.jar.pack; import java.io.*; @@ -62,20 +61,20 @@ class BandStructure implements Constants /** 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) { - throw new IOException( - "Package majver is already initialized to " + this.packageMajver+ - "; new setting is " + packageMajver); - } - this.packageMajver = packageMajver; - adjustToMajver(); + assert(packageMajver > 0 && packageMajver < 0x10000); + if (this.packageMajver > 0) { + throw new IOException( + "Package majver is already initialized to " + this.packageMajver+ + "; new setting is " + packageMajver); + } + this.packageMajver = packageMajver; + adjustToMajver(); } public int getPackageMajver() { - if (packageMajver < 0) { - throw new RuntimeException("Package majver not yet initialized"); - } - return packageMajver; + if (packageMajver < 0) { + throw new RuntimeException("Package majver not yet initialized"); + } + return packageMajver; } private final boolean isReader = this instanceof PackageReader; @@ -103,163 +102,163 @@ class BandStructure implements Constants final static Coding MDELTA5 = Coding.of(5,64,2).getDeltaCoding(); final private static Coding[] basicCodings = { - // Table of "Canonical BHSD Codings" from Pack200 spec. - null, // _meta_default + // Table of "Canonical BHSD Codings" from Pack200 spec. + null, // _meta_default - // Fixed-length codings: - Coding.of(1,256,0), - Coding.of(1,256,1), - Coding.of(1,256,0).getDeltaCoding(), - Coding.of(1,256,1).getDeltaCoding(), - Coding.of(2,256,0), - Coding.of(2,256,1), - Coding.of(2,256,0).getDeltaCoding(), - Coding.of(2,256,1).getDeltaCoding(), - Coding.of(3,256,0), - Coding.of(3,256,1), - Coding.of(3,256,0).getDeltaCoding(), - Coding.of(3,256,1).getDeltaCoding(), - Coding.of(4,256,0), - Coding.of(4,256,1), - Coding.of(4,256,0).getDeltaCoding(), - Coding.of(4,256,1).getDeltaCoding(), + // Fixed-length codings: + Coding.of(1,256,0), + Coding.of(1,256,1), + Coding.of(1,256,0).getDeltaCoding(), + Coding.of(1,256,1).getDeltaCoding(), + Coding.of(2,256,0), + Coding.of(2,256,1), + Coding.of(2,256,0).getDeltaCoding(), + Coding.of(2,256,1).getDeltaCoding(), + Coding.of(3,256,0), + Coding.of(3,256,1), + Coding.of(3,256,0).getDeltaCoding(), + Coding.of(3,256,1).getDeltaCoding(), + Coding.of(4,256,0), + Coding.of(4,256,1), + Coding.of(4,256,0).getDeltaCoding(), + Coding.of(4,256,1).getDeltaCoding(), - // Full-range variable-length codings: - Coding.of(5, 4,0), - Coding.of(5, 4,1), - Coding.of(5, 4,2), - Coding.of(5, 16,0), - Coding.of(5, 16,1), - Coding.of(5, 16,2), - Coding.of(5, 32,0), - Coding.of(5, 32,1), - Coding.of(5, 32,2), - Coding.of(5, 64,0), - Coding.of(5, 64,1), - Coding.of(5, 64,2), - Coding.of(5,128,0), - Coding.of(5,128,1), - Coding.of(5,128,2), + // Full-range variable-length codings: + Coding.of(5, 4,0), + Coding.of(5, 4,1), + Coding.of(5, 4,2), + Coding.of(5, 16,0), + Coding.of(5, 16,1), + Coding.of(5, 16,2), + Coding.of(5, 32,0), + Coding.of(5, 32,1), + Coding.of(5, 32,2), + Coding.of(5, 64,0), + Coding.of(5, 64,1), + Coding.of(5, 64,2), + Coding.of(5,128,0), + Coding.of(5,128,1), + Coding.of(5,128,2), - Coding.of(5, 4,0).getDeltaCoding(), - Coding.of(5, 4,1).getDeltaCoding(), - Coding.of(5, 4,2).getDeltaCoding(), - Coding.of(5, 16,0).getDeltaCoding(), - Coding.of(5, 16,1).getDeltaCoding(), - Coding.of(5, 16,2).getDeltaCoding(), - Coding.of(5, 32,0).getDeltaCoding(), - Coding.of(5, 32,1).getDeltaCoding(), - Coding.of(5, 32,2).getDeltaCoding(), - Coding.of(5, 64,0).getDeltaCoding(), - Coding.of(5, 64,1).getDeltaCoding(), - Coding.of(5, 64,2).getDeltaCoding(), - Coding.of(5,128,0).getDeltaCoding(), - Coding.of(5,128,1).getDeltaCoding(), - Coding.of(5,128,2).getDeltaCoding(), + Coding.of(5, 4,0).getDeltaCoding(), + Coding.of(5, 4,1).getDeltaCoding(), + Coding.of(5, 4,2).getDeltaCoding(), + Coding.of(5, 16,0).getDeltaCoding(), + Coding.of(5, 16,1).getDeltaCoding(), + Coding.of(5, 16,2).getDeltaCoding(), + Coding.of(5, 32,0).getDeltaCoding(), + Coding.of(5, 32,1).getDeltaCoding(), + Coding.of(5, 32,2).getDeltaCoding(), + Coding.of(5, 64,0).getDeltaCoding(), + Coding.of(5, 64,1).getDeltaCoding(), + Coding.of(5, 64,2).getDeltaCoding(), + Coding.of(5,128,0).getDeltaCoding(), + Coding.of(5,128,1).getDeltaCoding(), + Coding.of(5,128,2).getDeltaCoding(), - // Variable length subrange codings: - Coding.of(2,192,0), - Coding.of(2,224,0), - Coding.of(2,240,0), - Coding.of(2,248,0), - Coding.of(2,252,0), + // Variable length subrange codings: + Coding.of(2,192,0), + Coding.of(2,224,0), + Coding.of(2,240,0), + Coding.of(2,248,0), + Coding.of(2,252,0), - Coding.of(2, 8,0).getDeltaCoding(), - Coding.of(2, 8,1).getDeltaCoding(), - Coding.of(2, 16,0).getDeltaCoding(), - Coding.of(2, 16,1).getDeltaCoding(), - Coding.of(2, 32,0).getDeltaCoding(), - Coding.of(2, 32,1).getDeltaCoding(), - Coding.of(2, 64,0).getDeltaCoding(), - Coding.of(2, 64,1).getDeltaCoding(), - Coding.of(2,128,0).getDeltaCoding(), - Coding.of(2,128,1).getDeltaCoding(), - Coding.of(2,192,0).getDeltaCoding(), - Coding.of(2,192,1).getDeltaCoding(), - Coding.of(2,224,0).getDeltaCoding(), - Coding.of(2,224,1).getDeltaCoding(), - Coding.of(2,240,0).getDeltaCoding(), - Coding.of(2,240,1).getDeltaCoding(), - Coding.of(2,248,0).getDeltaCoding(), - Coding.of(2,248,1).getDeltaCoding(), + Coding.of(2, 8,0).getDeltaCoding(), + Coding.of(2, 8,1).getDeltaCoding(), + Coding.of(2, 16,0).getDeltaCoding(), + Coding.of(2, 16,1).getDeltaCoding(), + Coding.of(2, 32,0).getDeltaCoding(), + Coding.of(2, 32,1).getDeltaCoding(), + Coding.of(2, 64,0).getDeltaCoding(), + Coding.of(2, 64,1).getDeltaCoding(), + Coding.of(2,128,0).getDeltaCoding(), + Coding.of(2,128,1).getDeltaCoding(), + Coding.of(2,192,0).getDeltaCoding(), + Coding.of(2,192,1).getDeltaCoding(), + Coding.of(2,224,0).getDeltaCoding(), + Coding.of(2,224,1).getDeltaCoding(), + Coding.of(2,240,0).getDeltaCoding(), + Coding.of(2,240,1).getDeltaCoding(), + Coding.of(2,248,0).getDeltaCoding(), + Coding.of(2,248,1).getDeltaCoding(), - Coding.of(3,192,0), - Coding.of(3,224,0), - Coding.of(3,240,0), - Coding.of(3,248,0), - Coding.of(3,252,0), + Coding.of(3,192,0), + Coding.of(3,224,0), + Coding.of(3,240,0), + Coding.of(3,248,0), + Coding.of(3,252,0), - Coding.of(3, 8,0).getDeltaCoding(), - Coding.of(3, 8,1).getDeltaCoding(), - Coding.of(3, 16,0).getDeltaCoding(), - Coding.of(3, 16,1).getDeltaCoding(), - Coding.of(3, 32,0).getDeltaCoding(), - Coding.of(3, 32,1).getDeltaCoding(), - Coding.of(3, 64,0).getDeltaCoding(), - Coding.of(3, 64,1).getDeltaCoding(), - Coding.of(3,128,0).getDeltaCoding(), - Coding.of(3,128,1).getDeltaCoding(), - Coding.of(3,192,0).getDeltaCoding(), - Coding.of(3,192,1).getDeltaCoding(), - Coding.of(3,224,0).getDeltaCoding(), - Coding.of(3,224,1).getDeltaCoding(), - Coding.of(3,240,0).getDeltaCoding(), - Coding.of(3,240,1).getDeltaCoding(), - Coding.of(3,248,0).getDeltaCoding(), - Coding.of(3,248,1).getDeltaCoding(), + Coding.of(3, 8,0).getDeltaCoding(), + Coding.of(3, 8,1).getDeltaCoding(), + Coding.of(3, 16,0).getDeltaCoding(), + Coding.of(3, 16,1).getDeltaCoding(), + Coding.of(3, 32,0).getDeltaCoding(), + Coding.of(3, 32,1).getDeltaCoding(), + Coding.of(3, 64,0).getDeltaCoding(), + Coding.of(3, 64,1).getDeltaCoding(), + Coding.of(3,128,0).getDeltaCoding(), + Coding.of(3,128,1).getDeltaCoding(), + Coding.of(3,192,0).getDeltaCoding(), + Coding.of(3,192,1).getDeltaCoding(), + Coding.of(3,224,0).getDeltaCoding(), + Coding.of(3,224,1).getDeltaCoding(), + Coding.of(3,240,0).getDeltaCoding(), + Coding.of(3,240,1).getDeltaCoding(), + Coding.of(3,248,0).getDeltaCoding(), + Coding.of(3,248,1).getDeltaCoding(), - Coding.of(4,192,0), - Coding.of(4,224,0), - Coding.of(4,240,0), - Coding.of(4,248,0), - Coding.of(4,252,0), + Coding.of(4,192,0), + Coding.of(4,224,0), + Coding.of(4,240,0), + Coding.of(4,248,0), + Coding.of(4,252,0), - Coding.of(4, 8,0).getDeltaCoding(), - Coding.of(4, 8,1).getDeltaCoding(), - Coding.of(4, 16,0).getDeltaCoding(), - Coding.of(4, 16,1).getDeltaCoding(), - Coding.of(4, 32,0).getDeltaCoding(), - Coding.of(4, 32,1).getDeltaCoding(), - Coding.of(4, 64,0).getDeltaCoding(), - Coding.of(4, 64,1).getDeltaCoding(), - Coding.of(4,128,0).getDeltaCoding(), - Coding.of(4,128,1).getDeltaCoding(), - Coding.of(4,192,0).getDeltaCoding(), - Coding.of(4,192,1).getDeltaCoding(), - Coding.of(4,224,0).getDeltaCoding(), - Coding.of(4,224,1).getDeltaCoding(), - Coding.of(4,240,0).getDeltaCoding(), - Coding.of(4,240,1).getDeltaCoding(), - Coding.of(4,248,0).getDeltaCoding(), - Coding.of(4,248,1).getDeltaCoding(), + Coding.of(4, 8,0).getDeltaCoding(), + Coding.of(4, 8,1).getDeltaCoding(), + Coding.of(4, 16,0).getDeltaCoding(), + Coding.of(4, 16,1).getDeltaCoding(), + Coding.of(4, 32,0).getDeltaCoding(), + Coding.of(4, 32,1).getDeltaCoding(), + Coding.of(4, 64,0).getDeltaCoding(), + Coding.of(4, 64,1).getDeltaCoding(), + Coding.of(4,128,0).getDeltaCoding(), + Coding.of(4,128,1).getDeltaCoding(), + Coding.of(4,192,0).getDeltaCoding(), + Coding.of(4,192,1).getDeltaCoding(), + Coding.of(4,224,0).getDeltaCoding(), + Coding.of(4,224,1).getDeltaCoding(), + Coding.of(4,240,0).getDeltaCoding(), + Coding.of(4,240,1).getDeltaCoding(), + Coding.of(4,248,0).getDeltaCoding(), + Coding.of(4,248,1).getDeltaCoding(), - null + null }; final private static HashMap basicCodingIndexes; static { - assert(basicCodings[_meta_default] == null); - assert(basicCodings[_meta_canon_min] != null); - assert(basicCodings[_meta_canon_max] != null); - HashMap map = new HashMap(); - for (int i = 0; i < basicCodings.length; i++) { - Coding c = basicCodings[i]; - if (c == null) continue; - assert(i >= _meta_canon_min); - assert(i <= _meta_canon_max); - map.put(c, new Integer(i)); - } - basicCodingIndexes = map; + assert(basicCodings[_meta_default] == null); + assert(basicCodings[_meta_canon_min] != null); + assert(basicCodings[_meta_canon_max] != null); + HashMap map = new HashMap(); + for (int i = 0; i < basicCodings.length; i++) { + Coding c = basicCodings[i]; + if (c == null) continue; + assert(i >= _meta_canon_min); + assert(i <= _meta_canon_max); + map.put(c, new Integer(i)); + } + basicCodingIndexes = map; } public static Coding codingForIndex(int i) { - return i < basicCodings.length ? basicCodings[i] : null; + return i < basicCodings.length ? basicCodings[i] : null; } public static int indexOf(Coding c) { - Integer i = (Integer) basicCodingIndexes.get(c); - if (i == null) return 0; - return i.intValue(); + Integer i = (Integer) basicCodingIndexes.get(c); + if (i == null) return 0; + return i.intValue(); } public static Coding[] getBasicCodings() { - return (Coding[]) basicCodings.clone(); + return (Coding[]) basicCodings.clone(); } protected byte[] bandHeaderBytes; // used for input only @@ -267,31 +266,31 @@ class BandStructure implements Constants protected int bandHeaderBytePos0; // for debug protected CodingMethod getBandHeader(int XB, Coding regularCoding) { - CodingMethod[] res = {null}; - // push back XB onto the band header bytes - bandHeaderBytes[--bandHeaderBytePos] = (byte) XB; - bandHeaderBytePos0 = bandHeaderBytePos; - // scan forward through XB and any additional band header bytes - bandHeaderBytePos = parseMetaCoding(bandHeaderBytes, - bandHeaderBytePos, - regularCoding, - res); - return res[0]; + CodingMethod[] res = {null}; + // push back XB onto the band header bytes + bandHeaderBytes[--bandHeaderBytePos] = (byte) XB; + bandHeaderBytePos0 = bandHeaderBytePos; + // scan forward through XB and any additional band header bytes + bandHeaderBytePos = parseMetaCoding(bandHeaderBytes, + bandHeaderBytePos, + regularCoding, + res); + return res[0]; } public static int parseMetaCoding(byte[] bytes, int pos, Coding dflt, CodingMethod[] res) { - if ((bytes[pos] & 0xFF) == _meta_default) { - res[0] = dflt; - return pos+1; - } - int pos2; - pos2 = Coding.parseMetaCoding(bytes, pos, dflt, res); - if (pos2 > pos) return pos2; - pos2 = PopulationCoding.parseMetaCoding(bytes, pos, dflt, res); - if (pos2 > pos) return pos2; - pos2 = AdaptiveCoding.parseMetaCoding(bytes, pos, dflt, res); - if (pos2 > pos) return pos2; - throw new RuntimeException("Bad meta-coding op "+(bytes[pos]&0xFF)); + if ((bytes[pos] & 0xFF) == _meta_default) { + res[0] = dflt; + return pos+1; + } + int pos2; + pos2 = Coding.parseMetaCoding(bytes, pos, dflt, res); + if (pos2 > pos) return pos2; + pos2 = PopulationCoding.parseMetaCoding(bytes, pos, dflt, res); + if (pos2 > pos) return pos2; + pos2 = AdaptiveCoding.parseMetaCoding(bytes, pos, dflt, res); + if (pos2 > pos) return pos2; + throw new RuntimeException("Bad meta-coding op "+(bytes[pos]&0xFF)); } static final int SHORT_BAND_HEURISTIC = 100; @@ -311,11 +310,11 @@ class BandStructure implements Constants public static final int DONE_PHASE = 8; // done writing or reading static boolean phaseIsRead(int p) { - return (p % 2) == 0; + return (p % 2) == 0; } static int phaseCmp(int p0, int p1) { - assert((p0 % 2) == (p1 % 2) || (p0 % 8) == 0 || (p1 % 8) == 0); - return p0 - p1; + assert((p0 % 2) == (p1 % 2) || (p0 % 8) == 0 || (p1 % 8) == 0); + return p0 - p1; } /** The packed file is divided up into a number of segments. @@ -332,7 +331,7 @@ class BandStructure implements Constants * * The three phases for reading a packed file are EXPECT, READ, * and DISBURSE. - * 1. For each band, the expected number of integers is determined. + * 1. For each band, the expected number of integers is determined. * 2. The data is actually read from the file into the band. * 3. The band pays out its values as requested, in an ad hoc order. * @@ -340,696 +339,695 @@ class BandStructure implements Constants * Clearly, these phases must be properly ordered WRT each other. */ abstract class Band { - private int phase = NO_PHASE; - private final String name; + private int phase = NO_PHASE; + private final String name; - private int valuesExpected; + private int valuesExpected; - protected long outputSize = -1; // cache + protected long outputSize = -1; // cache - final public Coding regularCoding; + final public Coding regularCoding; - final public int seqForDebug; - public int elementCountForDebug; + final public int seqForDebug; + public int elementCountForDebug; - protected Band(String name, Coding regularCoding) { - this.name = name; - this.regularCoding = regularCoding; - this.seqForDebug = ++nextSeqForDebug; - if (verbose > 2) - Utils.log.fine("Band "+seqForDebug+" is "+name); - // caller must call init - } + protected Band(String name, Coding regularCoding) { + this.name = name; + this.regularCoding = regularCoding; + this.seqForDebug = ++nextSeqForDebug; + if (verbose > 2) + Utils.log.fine("Band "+seqForDebug+" is "+name); + // caller must call init + } - public Band init() { - // Cannot due this from the constructor, because constructor - // may wish to initialize some subclass variables. - // Set initial phase for reading or writing: - if (isReader) - readyToExpect(); - else - readyToCollect(); - return this; - } + public Band init() { + // Cannot due this from the constructor, because constructor + // may wish to initialize some subclass variables. + // Set initial phase for reading or writing: + if (isReader) + readyToExpect(); + else + readyToCollect(); + return this; + } - // common operations - boolean isReader() { return isReader; } - int phase() { return phase; } - String name() { return name; } + // common operations + boolean isReader() { return isReader; } + int phase() { return phase; } + String name() { return name; } - /** Return -1 if data buffer not allocated, else max length. */ - public abstract int capacity(); + /** Return -1 if data buffer not allocated, else max length. */ + public abstract int capacity(); - /** Allocate data buffer to specified length. */ - protected abstract void setCapacity(int cap); + /** Allocate data buffer to specified length. */ + protected abstract void setCapacity(int cap); - /** Return current number of values in buffer, which must exist. */ - public abstract int length(); + /** Return current number of values in buffer, which must exist. */ + public abstract int length(); - protected abstract int valuesRemainingForDebug(); + protected abstract int valuesRemainingForDebug(); - public final int valuesExpected() { - return valuesExpected; - } + public final int valuesExpected() { + return valuesExpected; + } - /** Write out bytes, encoding the values. */ - public final void writeTo(OutputStream out) throws IOException { - assert(assertReadyToWriteTo(this, out)); - setPhase(WRITE_PHASE); - // subclasses continue by writing their contents to output - writeDataTo(out); - doneWriting(); - } + /** Write out bytes, encoding the values. */ + public final void writeTo(OutputStream out) throws IOException { + assert(assertReadyToWriteTo(this, out)); + setPhase(WRITE_PHASE); + // subclasses continue by writing their contents to output + writeDataTo(out); + doneWriting(); + } - abstract void chooseBandCodings() throws IOException; + abstract void chooseBandCodings() throws IOException; - public final long outputSize() { - if (outputSize >= 0) { - long size = outputSize; - assert(size == computeOutputSize()); - return size; - } - return computeOutputSize(); - } + public final long outputSize() { + if (outputSize >= 0) { + long size = outputSize; + assert(size == computeOutputSize()); + return size; + } + return computeOutputSize(); + } - protected abstract long computeOutputSize(); + protected abstract long computeOutputSize(); - abstract protected void writeDataTo(OutputStream out) throws IOException; + abstract protected void writeDataTo(OutputStream out) throws IOException; - /** Expect a certain number of values. */ - void expectLength(int l) { - assert(assertPhase(this, EXPECT_PHASE)); - assert(valuesExpected == 0); // all at once - assert(l >= 0); - valuesExpected = l; - } - /** Expect more values. (Multiple calls accumulate.) */ - void expectMoreLength(int l) { - assert(assertPhase(this, EXPECT_PHASE)); - valuesExpected += l; - } + /** Expect a certain number of values. */ + void expectLength(int l) { + assert(assertPhase(this, EXPECT_PHASE)); + assert(valuesExpected == 0); // all at once + assert(l >= 0); + valuesExpected = l; + } + /** Expect more values. (Multiple calls accumulate.) */ + void expectMoreLength(int l) { + assert(assertPhase(this, EXPECT_PHASE)); + valuesExpected += l; + } - /// Phase change markers. + /// Phase change markers. - private void readyToCollect() { // called implicitly by constructor - setCapacity(1); - setPhase(COLLECT_PHASE); - } - protected void doneWriting() { - assert(assertPhase(this, WRITE_PHASE)); - setPhase(DONE_PHASE); - } - private void readyToExpect() { // called implicitly by constructor - setPhase(EXPECT_PHASE); - } - /** Read in bytes, decoding the values. */ - public final void readFrom(InputStream in) throws IOException { - assert(assertReadyToReadFrom(this, in)); - setCapacity(valuesExpected()); - setPhase(READ_PHASE); - // subclasses continue by reading their contents from input: - readDataFrom(in); - readyToDisburse(); - } - abstract protected void readDataFrom(InputStream in) throws IOException; - protected void readyToDisburse() { - if (verbose > 1) Utils.log.fine("readyToDisburse "+this); - setPhase(DISBURSE_PHASE); - } - public void doneDisbursing() { - assert(assertPhase(this, DISBURSE_PHASE)); - setPhase(DONE_PHASE); - } - public final void doneWithUnusedBand() { - if (isReader) { - assert(assertPhase(this, EXPECT_PHASE)); - assert(valuesExpected() == 0); - // Fast forward: - setPhase(READ_PHASE); - setPhase(DISBURSE_PHASE); - setPhase(DONE_PHASE); - } else { - setPhase(FROZEN_PHASE); - } - } + private void readyToCollect() { // called implicitly by constructor + setCapacity(1); + setPhase(COLLECT_PHASE); + } + protected void doneWriting() { + assert(assertPhase(this, WRITE_PHASE)); + setPhase(DONE_PHASE); + } + private void readyToExpect() { // called implicitly by constructor + setPhase(EXPECT_PHASE); + } + /** Read in bytes, decoding the values. */ + public final void readFrom(InputStream in) throws IOException { + assert(assertReadyToReadFrom(this, in)); + setCapacity(valuesExpected()); + setPhase(READ_PHASE); + // subclasses continue by reading their contents from input: + readDataFrom(in); + readyToDisburse(); + } + abstract protected void readDataFrom(InputStream in) throws IOException; + protected void readyToDisburse() { + if (verbose > 1) Utils.log.fine("readyToDisburse "+this); + setPhase(DISBURSE_PHASE); + } + public void doneDisbursing() { + assert(assertPhase(this, DISBURSE_PHASE)); + setPhase(DONE_PHASE); + } + public final void doneWithUnusedBand() { + if (isReader) { + assert(assertPhase(this, EXPECT_PHASE)); + assert(valuesExpected() == 0); + // Fast forward: + setPhase(READ_PHASE); + setPhase(DISBURSE_PHASE); + setPhase(DONE_PHASE); + } else { + setPhase(FROZEN_PHASE); + } + } - protected void setPhase(int newPhase) { - assert(assertPhaseChangeOK(this, phase, newPhase)); - this.phase = newPhase; - } + protected void setPhase(int newPhase) { + assert(assertPhaseChangeOK(this, phase, newPhase)); + this.phase = newPhase; + } - protected int lengthForDebug = -1; // DEBUG ONLY - public String toString() { // DEBUG ONLY - int length = (lengthForDebug != -1 ? lengthForDebug : length()); - String str = name; - if (length != 0) - str += "[" + length + "]"; - if (elementCountForDebug != 0) - str += "(" + elementCountForDebug + ")"; - return str; - } + protected int lengthForDebug = -1; // DEBUG ONLY + public String toString() { // DEBUG ONLY + int length = (lengthForDebug != -1 ? lengthForDebug : length()); + String str = name; + if (length != 0) + str += "[" + length + "]"; + if (elementCountForDebug != 0) + str += "(" + elementCountForDebug + ")"; + return str; + } } class ValueBand extends Band { - private int[] values; // must be null in EXPECT phase - private int length; - private int valuesDisbursed; + private int[] values; // must be null in EXPECT phase + private int length; + private int valuesDisbursed; - private CodingMethod bandCoding; - private byte[] metaCoding; + private CodingMethod bandCoding; + private byte[] metaCoding; - protected ValueBand(String name, Coding regularCoding) { - super(name, regularCoding); - } + protected ValueBand(String name, Coding regularCoding) { + super(name, regularCoding); + } - public int capacity() { - return values == null ? -1 : values.length; - } + public int capacity() { + return values == null ? -1 : values.length; + } - /** Declare predicted or needed capacity. */ - protected void setCapacity(int cap) { - assert(length <= cap); - if (cap == -1) { values = null; return; } - values = realloc(values, cap); - } + /** Declare predicted or needed capacity. */ + protected void setCapacity(int cap) { + assert(length <= cap); + if (cap == -1) { values = null; return; } + values = realloc(values, cap); + } - public int length() { - return length; - } - protected int valuesRemainingForDebug() { - return length - valuesDisbursed; - } - protected int valueAtForDebug(int i) { - return values[i]; - } + public int length() { + return length; + } + protected int valuesRemainingForDebug() { + return length - valuesDisbursed; + } + protected int valueAtForDebug(int i) { + return values[i]; + } - void patchValue(int i, int value) { - // Only one use for this. - assert(this == archive_header_S); - assert(i == AH_ARCHIVE_SIZE_HI || i == AH_ARCHIVE_SIZE_LO); - assert(i < length); // must have already output a dummy - values[i] = value; - outputSize = -1; // decache - } + void patchValue(int i, int value) { + // Only one use for this. + assert(this == archive_header_S); + assert(i == AH_ARCHIVE_SIZE_HI || i == AH_ARCHIVE_SIZE_LO); + assert(i < length); // must have already output a dummy + values[i] = value; + outputSize = -1; // decache + } - protected void initializeValues(int[] values) { - assert(assertCanChangeLength(this)); - assert(length == 0); - this.values = values; - this.length = values.length; - } + protected void initializeValues(int[] values) { + assert(assertCanChangeLength(this)); + assert(length == 0); + this.values = values; + this.length = values.length; + } - /** Collect one value, or store one decoded value. */ - protected void addValue(int x) { - assert(assertCanChangeLength(this)); - if (length == values.length) - setCapacity(length < 1000 ? length * 10 : length * 2); - values[length++] = x; - } + /** Collect one value, or store one decoded value. */ + protected void addValue(int x) { + assert(assertCanChangeLength(this)); + if (length == values.length) + setCapacity(length < 1000 ? length * 10 : length * 2); + values[length++] = x; + } - private boolean canVaryCoding() { - if (!optVaryCodings) return false; - if (length == 0) return false; - // Can't read band_headers w/o the archive header: - if (this == archive_header_0) return false; - if (this == archive_header_S) return false; - if (this == archive_header_1) return false; - // BYTE1 bands can't vary codings, but the others can. - // All that's needed for the initial escape is at least - // 256 negative values or more than 256 non-negative values - return (regularCoding.min() <= -256 || regularCoding.max() >= 256); - } + private boolean canVaryCoding() { + if (!optVaryCodings) return false; + if (length == 0) return false; + // Can't read band_headers w/o the archive header: + if (this == archive_header_0) return false; + if (this == archive_header_S) return false; + if (this == archive_header_1) return false; + // BYTE1 bands can't vary codings, but the others can. + // All that's needed for the initial escape is at least + // 256 negative values or more than 256 non-negative values + return (regularCoding.min() <= -256 || regularCoding.max() >= 256); + } - private boolean shouldVaryCoding() { - assert(canVaryCoding()); - if (effort < MAX_EFFORT && length < SHORT_BAND_HEURISTIC) - return false; - return true; - } + private boolean shouldVaryCoding() { + assert(canVaryCoding()); + if (effort < MAX_EFFORT && length < SHORT_BAND_HEURISTIC) + return false; + return true; + } - protected void chooseBandCodings() throws IOException { - boolean canVary = canVaryCoding(); - if (!canVary || !shouldVaryCoding()) { - if (regularCoding.canRepresent(values, 0, length)) { - bandCoding = regularCoding; - } else { - assert(canVary); - if (verbose > 1) - Utils.log.fine("regular coding fails in band "+name()); - bandCoding = UNSIGNED5; - } - outputSize = -1; - } else { - int[] sizes = {0,0}; - bandCoding = chooseCoding(values, 0, length, - regularCoding, name(), - sizes); - outputSize = sizes[CodingChooser.BYTE_SIZE]; - if (outputSize == 0) // CodingChooser failed to size it. - outputSize = -1; - } + protected void chooseBandCodings() throws IOException { + boolean canVary = canVaryCoding(); + if (!canVary || !shouldVaryCoding()) { + if (regularCoding.canRepresent(values, 0, length)) { + bandCoding = regularCoding; + } else { + assert(canVary); + if (verbose > 1) + Utils.log.fine("regular coding fails in band "+name()); + bandCoding = UNSIGNED5; + } + outputSize = -1; + } else { + int[] sizes = {0,0}; + bandCoding = chooseCoding(values, 0, length, + regularCoding, name(), + sizes); + outputSize = sizes[CodingChooser.BYTE_SIZE]; + if (outputSize == 0) // CodingChooser failed to size it. + outputSize = -1; + } - // Compute and save the meta-coding bytes also. - if (bandCoding != regularCoding) { - metaCoding = bandCoding.getMetaCoding(regularCoding); - if (verbose > 1) { - Utils.log.fine("alternate coding "+this+" "+bandCoding); - } - } else if (canVary && - decodeEscapeValue(values[0], regularCoding) >= 0) { - // Need an explicit default. - metaCoding = defaultMetaCoding; - } else { - // Common case: Zero bytes of meta coding. - metaCoding = noMetaCoding; - } - if (metaCoding.length > 0 - && (verbose > 2 || verbose > 1 && metaCoding.length > 1)) { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < metaCoding.length; i++) { - if (i == 1) sb.append(" /"); - sb.append(" ").append(metaCoding[i] & 0xFF); - } - Utils.log.fine(" meta-coding "+sb); - } + // Compute and save the meta-coding bytes also. + if (bandCoding != regularCoding) { + metaCoding = bandCoding.getMetaCoding(regularCoding); + if (verbose > 1) { + Utils.log.fine("alternate coding "+this+" "+bandCoding); + } + } else if (canVary && + decodeEscapeValue(values[0], regularCoding) >= 0) { + // Need an explicit default. + metaCoding = defaultMetaCoding; + } else { + // Common case: Zero bytes of meta coding. + metaCoding = noMetaCoding; + } + if (metaCoding.length > 0 + && (verbose > 2 || verbose > 1 && metaCoding.length > 1)) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < metaCoding.length; i++) { + if (i == 1) sb.append(" /"); + sb.append(" ").append(metaCoding[i] & 0xFF); + } + Utils.log.fine(" meta-coding "+sb); + } - assert((outputSize < 0) || - !(bandCoding instanceof Coding) || - (outputSize == ((Coding)bandCoding) - .getLength(values, 0, length))) - : (bandCoding+" : "+ - outputSize+" != "+ - ((Coding)bandCoding).getLength(values, 0, length) - +" ?= "+getCodingChooser().computeByteSize(bandCoding,values,0,length) - ); + assert((outputSize < 0) || + !(bandCoding instanceof Coding) || + (outputSize == ((Coding)bandCoding) + .getLength(values, 0, length))) + : (bandCoding+" : "+ + outputSize+" != "+ + ((Coding)bandCoding).getLength(values, 0, length) + +" ?= "+getCodingChooser().computeByteSize(bandCoding,values,0,length) + ); - // Compute outputSize of the escape value X, if any. - if (metaCoding.length > 0) { - // First byte XB of meta-coding is treated specially, - // but any other bytes go into the band headers band. - // This must be done before any other output happens. - if (outputSize >= 0) - outputSize += computeEscapeSize(); // good cache - // Other bytes go into band_headers. - for (int i = 1; i < metaCoding.length; i++) { - band_headers.putByte(metaCoding[i] & 0xFF); - } - } - } + // Compute outputSize of the escape value X, if any. + if (metaCoding.length > 0) { + // First byte XB of meta-coding is treated specially, + // but any other bytes go into the band headers band. + // This must be done before any other output happens. + if (outputSize >= 0) + outputSize += computeEscapeSize(); // good cache + // Other bytes go into band_headers. + for (int i = 1; i < metaCoding.length; i++) { + band_headers.putByte(metaCoding[i] & 0xFF); + } + } + } - protected long computeOutputSize() { - outputSize = getCodingChooser().computeByteSize(bandCoding, - values, 0, length); - assert(outputSize < Integer.MAX_VALUE); - outputSize += computeEscapeSize(); - return outputSize; - } + protected long computeOutputSize() { + outputSize = getCodingChooser().computeByteSize(bandCoding, + values, 0, length); + assert(outputSize < Integer.MAX_VALUE); + outputSize += computeEscapeSize(); + return outputSize; + } - protected int computeEscapeSize() { - if (metaCoding.length == 0) return 0; - int XB = metaCoding[0] & 0xFF; - int X = encodeEscapeValue(XB, regularCoding); - return regularCoding.setD(0).getLength(X); - } + protected int computeEscapeSize() { + if (metaCoding.length == 0) return 0; + int XB = metaCoding[0] & 0xFF; + int X = encodeEscapeValue(XB, regularCoding); + return regularCoding.setD(0).getLength(X); + } - protected void writeDataTo(OutputStream out) throws IOException { - if (length == 0) return; // nothing to write - long len0 = 0; - if (out == outputCounter) { - len0 = outputCounter.getCount(); - } - if (metaCoding.length > 0) { - int XB = metaCoding[0] & 0xFF; - // We need an explicit band header, either because - // there is a non-default coding method, or because - // the first value would be parsed as an escape value. - int X = encodeEscapeValue(XB, regularCoding); - //System.out.println("X="+X+" XB="+XB+" in "+this); - regularCoding.setD(0).writeTo(out, X); - } - bandCoding.writeArrayTo(out, values, 0, length); - if (out == outputCounter) { - long len1 = outputCounter.getCount(); - assert(outputSize == outputCounter.getCount() - len0) - : (outputSize+" != "+outputCounter.getCount()+"-"+len0); - } - if (optDumpBands) dumpBand(); - } + protected void writeDataTo(OutputStream out) throws IOException { + if (length == 0) return; // nothing to write + long len0 = 0; + if (out == outputCounter) { + len0 = outputCounter.getCount(); + } + if (metaCoding.length > 0) { + int XB = metaCoding[0] & 0xFF; + // We need an explicit band header, either because + // there is a non-default coding method, or because + // the first value would be parsed as an escape value. + int X = encodeEscapeValue(XB, regularCoding); + //System.out.println("X="+X+" XB="+XB+" in "+this); + regularCoding.setD(0).writeTo(out, X); + } + bandCoding.writeArrayTo(out, values, 0, length); + if (out == outputCounter) { + long len1 = outputCounter.getCount(); + assert(outputSize == outputCounter.getCount() - len0) + : (outputSize+" != "+outputCounter.getCount()+"-"+len0); + } + if (optDumpBands) dumpBand(); + } - protected void readDataFrom(InputStream in) throws IOException { - length = valuesExpected(); - if (length == 0) return; // nothing to read - if (verbose > 1) - Utils.log.fine("Reading band "+this); - if (!canVaryCoding()) { - bandCoding = regularCoding; - metaCoding = noMetaCoding; - } else { - assert(in.markSupported()); // input must be buffered - in.mark(Coding.B_MAX); - int X = regularCoding.setD(0).readFrom(in); - int XB = decodeEscapeValue(X, regularCoding); - if (XB < 0) { - // Do not consume this value. No alternate coding. - in.reset(); - XB = _meta_default; - bandCoding = regularCoding; - metaCoding = noMetaCoding; - } else if (XB == _meta_default) { - bandCoding = regularCoding; - metaCoding = defaultMetaCoding; - } else { - if (verbose > 2) - Utils.log.fine("found X="+X+" => XB="+XB); - bandCoding = getBandHeader(XB, regularCoding); - // This is really used only by dumpBands. - int p0 = bandHeaderBytePos0; - int p1 = bandHeaderBytePos; - metaCoding = new byte[p1-p0]; - System.arraycopy(bandHeaderBytes, p0, - metaCoding, 0, metaCoding.length); - } - } - if (bandCoding != regularCoding) { - if (verbose > 1) - Utils.log.fine(name()+": irregular coding "+bandCoding); - } - bandCoding.readArrayFrom(in, values, 0, length); - if (optDumpBands) dumpBand(); - } + protected void readDataFrom(InputStream in) throws IOException { + length = valuesExpected(); + if (length == 0) return; // nothing to read + if (verbose > 1) + Utils.log.fine("Reading band "+this); + if (!canVaryCoding()) { + bandCoding = regularCoding; + metaCoding = noMetaCoding; + } else { + assert(in.markSupported()); // input must be buffered + in.mark(Coding.B_MAX); + int X = regularCoding.setD(0).readFrom(in); + int XB = decodeEscapeValue(X, regularCoding); + if (XB < 0) { + // Do not consume this value. No alternate coding. + in.reset(); + XB = _meta_default; + bandCoding = regularCoding; + metaCoding = noMetaCoding; + } else if (XB == _meta_default) { + bandCoding = regularCoding; + metaCoding = defaultMetaCoding; + } else { + if (verbose > 2) + Utils.log.fine("found X="+X+" => XB="+XB); + bandCoding = getBandHeader(XB, regularCoding); + // This is really used only by dumpBands. + int p0 = bandHeaderBytePos0; + int p1 = bandHeaderBytePos; + metaCoding = new byte[p1-p0]; + System.arraycopy(bandHeaderBytes, p0, + metaCoding, 0, metaCoding.length); + } + } + if (bandCoding != regularCoding) { + if (verbose > 1) + Utils.log.fine(name()+": irregular coding "+bandCoding); + } + bandCoding.readArrayFrom(in, values, 0, length); + if (optDumpBands) dumpBand(); + } - public void doneDisbursing() { - super.doneDisbursing(); - values = null; // for GC - } + public void doneDisbursing() { + super.doneDisbursing(); + values = null; // for GC + } - private void dumpBand() throws IOException { - assert(optDumpBands); - PrintStream ps = new PrintStream(getDumpStream(this, ".txt")); - String irr = (bandCoding == regularCoding) ? "" : " irregular"; - ps.print("# length="+length+ - " size="+outputSize()+ - irr+" coding="+bandCoding); - if (metaCoding != noMetaCoding) { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < metaCoding.length; i++) { - if (i == 1) sb.append(" /"); - sb.append(" ").append(metaCoding[i] & 0xFF); - } - ps.print(" //header: "+sb); - } - printArrayTo(ps, values, 0, length); - ps.close(); - OutputStream ds = getDumpStream(this, ".bnd"); - bandCoding.writeArrayTo(ds, values, 0, length); - ds.close(); - } + private void dumpBand() throws IOException { + assert(optDumpBands); + PrintStream ps = new PrintStream(getDumpStream(this, ".txt")); + String irr = (bandCoding == regularCoding) ? "" : " irregular"; + ps.print("# length="+length+ + " size="+outputSize()+ + irr+" coding="+bandCoding); + if (metaCoding != noMetaCoding) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < metaCoding.length; i++) { + if (i == 1) sb.append(" /"); + sb.append(" ").append(metaCoding[i] & 0xFF); + } + ps.print(" //header: "+sb); + } + printArrayTo(ps, values, 0, length); + ps.close(); + OutputStream ds = getDumpStream(this, ".bnd"); + bandCoding.writeArrayTo(ds, values, 0, length); + ds.close(); + } - /** Disburse one value. */ - protected int getValue() { - assert(phase() == DISBURSE_PHASE); - assert(valuesDisbursed < length); - return values[valuesDisbursed++]; - } + /** Disburse one value. */ + protected int getValue() { + assert(phase() == DISBURSE_PHASE); + assert(valuesDisbursed < length); + return values[valuesDisbursed++]; + } - /** Reset for another pass over the same value set. */ - public void resetForSecondPass() { - assert(phase() == DISBURSE_PHASE); - assert(valuesDisbursed == length()); // 1st pass is complete - valuesDisbursed = 0; - } + /** Reset for another pass over the same value set. */ + public void resetForSecondPass() { + assert(phase() == DISBURSE_PHASE); + assert(valuesDisbursed == length()); // 1st pass is complete + valuesDisbursed = 0; + } } class ByteBand extends Band { - private ByteArrayOutputStream bytes; // input buffer - private ByteArrayOutputStream bytesForDump; - private InputStream in; + private ByteArrayOutputStream bytes; // input buffer + private ByteArrayOutputStream bytesForDump; + private InputStream in; - public ByteBand(String name) { - super(name, BYTE1); - } + public ByteBand(String name) { + super(name, BYTE1); + } - public int capacity() { - return bytes == null ? -1 : Integer.MAX_VALUE; - } - protected void setCapacity(int cap) { - assert(bytes == null); // do this just once - bytes = new ByteArrayOutputStream(cap); - } - public void destroy() { - lengthForDebug = length(); - bytes = null; - } + public int capacity() { + return bytes == null ? -1 : Integer.MAX_VALUE; + } + protected void setCapacity(int cap) { + assert(bytes == null); // do this just once + bytes = new ByteArrayOutputStream(cap); + } + public void destroy() { + lengthForDebug = length(); + bytes = null; + } - public int length() { - return bytes == null ? -1 : bytes.size(); - } - public void reset() { - bytes.reset(); - } - protected int valuesRemainingForDebug() { - return (bytes == null) ? -1 : ((ByteArrayInputStream)in).available(); - } + public int length() { + return bytes == null ? -1 : bytes.size(); + } + public void reset() { + bytes.reset(); + } + protected int valuesRemainingForDebug() { + return (bytes == null) ? -1 : ((ByteArrayInputStream)in).available(); + } - protected void chooseBandCodings() throws IOException { - // No-op. - assert(decodeEscapeValue(regularCoding.min(), regularCoding) < 0); - assert(decodeEscapeValue(regularCoding.max(), regularCoding) < 0); - } + protected void chooseBandCodings() throws IOException { + // No-op. + assert(decodeEscapeValue(regularCoding.min(), regularCoding) < 0); + assert(decodeEscapeValue(regularCoding.max(), regularCoding) < 0); + } - protected long computeOutputSize() { - // do not cache - return bytes.size(); - } + protected long computeOutputSize() { + // do not cache + return bytes.size(); + } - public void writeDataTo(OutputStream out) throws IOException { - if (length() == 0) return; - bytes.writeTo(out); - if (optDumpBands) dumpBand(); - destroy(); // done with the bits! - } + public void writeDataTo(OutputStream out) throws IOException { + if (length() == 0) return; + bytes.writeTo(out); + if (optDumpBands) dumpBand(); + destroy(); // done with the bits! + } - private void dumpBand() throws IOException { - assert(optDumpBands); - OutputStream ds = getDumpStream(this, ".bnd"); - if (bytesForDump != null) - bytesForDump.writeTo(ds); - else - bytes.writeTo(ds); - ds.close(); - } + private void dumpBand() throws IOException { + assert(optDumpBands); + OutputStream ds = getDumpStream(this, ".bnd"); + if (bytesForDump != null) + bytesForDump.writeTo(ds); + else + bytes.writeTo(ds); + ds.close(); + } - public void readDataFrom(InputStream in) throws IOException { - int vex = valuesExpected(); - if (vex == 0) return; - if (verbose > 1) { - lengthForDebug = vex; - Utils.log.fine("Reading band "+this); - lengthForDebug = -1; - } - byte[] buf = new byte[Math.min(vex, 1<<14)]; - while (vex > 0) { - int nr = in.read(buf, 0, Math.min(vex, buf.length)); - if (nr < 0) throw new EOFException(); - bytes.write(buf, 0, nr); - vex -= nr; - } - if (optDumpBands) dumpBand(); - } + public void readDataFrom(InputStream in) throws IOException { + int vex = valuesExpected(); + if (vex == 0) return; + if (verbose > 1) { + lengthForDebug = vex; + Utils.log.fine("Reading band "+this); + lengthForDebug = -1; + } + byte[] buf = new byte[Math.min(vex, 1<<14)]; + while (vex > 0) { + int nr = in.read(buf, 0, Math.min(vex, buf.length)); + if (nr < 0) throw new EOFException(); + bytes.write(buf, 0, nr); + vex -= nr; + } + if (optDumpBands) dumpBand(); + } - public void readyToDisburse() { - in = new ByteArrayInputStream(bytes.toByteArray()); - super.readyToDisburse(); - } + public void readyToDisburse() { + in = new ByteArrayInputStream(bytes.toByteArray()); + super.readyToDisburse(); + } - public void doneDisbursing() { - super.doneDisbursing(); - if (optDumpBands - && bytesForDump != null && bytesForDump.size() > 0) { - try { - dumpBand(); - } catch (IOException ee) { - throw new RuntimeException(ee); - } - } - in = null; // GC - bytes = null; // GC - bytesForDump = null; // GC - } + public void doneDisbursing() { + super.doneDisbursing(); + if (optDumpBands + && bytesForDump != null && bytesForDump.size() > 0) { + try { + dumpBand(); + } catch (IOException ee) { + throw new RuntimeException(ee); + } + } + in = null; // GC + bytes = null; // GC + bytesForDump = null; // GC + } - // alternative to readFrom: - public void setInputStreamFrom(InputStream in) throws IOException { - assert(bytes == null); - assert(assertReadyToReadFrom(this, in)); - setPhase(READ_PHASE); - this.in = in; - if (optDumpBands) { - // Tap the stream. - bytesForDump = new ByteArrayOutputStream(); - this.in = new FilterInputStream(in) { - public int read() throws IOException { - int ch = in.read(); - if (ch >= 0) bytesForDump.write(ch); - return ch; - } - public int read(byte b[], int off, int len) throws IOException { - int nr = in.read(b, off, len); - if (nr >= 0) bytesForDump.write(b, off, nr); - return nr; - } - }; - } - super.readyToDisburse(); - } + // alternative to readFrom: + public void setInputStreamFrom(InputStream in) throws IOException { + assert(bytes == null); + assert(assertReadyToReadFrom(this, in)); + setPhase(READ_PHASE); + this.in = in; + if (optDumpBands) { + // Tap the stream. + bytesForDump = new ByteArrayOutputStream(); + this.in = new FilterInputStream(in) { + public int read() throws IOException { + int ch = in.read(); + if (ch >= 0) bytesForDump.write(ch); + return ch; + } + public int read(byte b[], int off, int len) throws IOException { + int nr = in.read(b, off, len); + if (nr >= 0) bytesForDump.write(b, off, nr); + return nr; + } + }; + } + super.readyToDisburse(); + } - public OutputStream collectorStream() { - assert(phase() == COLLECT_PHASE); - assert(bytes != null); - return bytes; - } + public OutputStream collectorStream() { + assert(phase() == COLLECT_PHASE); + assert(bytes != null); + return bytes; + } - public InputStream getInputStream() { - assert(phase() == DISBURSE_PHASE); - assert(in != null); - return in; - } - public int getByte() throws IOException { - int b = getInputStream().read(); - if (b < 0) throw new EOFException(); - return b; - } - public void putByte(int b) throws IOException { - assert(b == (b & 0xFF)); - collectorStream().write(b); - } - public String toString() { - return "byte "+super.toString(); - } + public InputStream getInputStream() { + assert(phase() == DISBURSE_PHASE); + assert(in != null); + return in; + } + public int getByte() throws IOException { + int b = getInputStream().read(); + if (b < 0) throw new EOFException(); + return b; + } + public void putByte(int b) throws IOException { + assert(b == (b & 0xFF)); + collectorStream().write(b); + } + public String toString() { + return "byte "+super.toString(); + } } class IntBand extends ValueBand { - // The usual coding for bands is 7bit/5byte/delta. - public IntBand(String name, Coding regularCoding) { - super(name, regularCoding); - } + // The usual coding for bands is 7bit/5byte/delta. + public IntBand(String name, Coding regularCoding) { + super(name, regularCoding); + } - public void putInt(int x) { - assert(phase() == COLLECT_PHASE); - addValue(x); - } + public void putInt(int x) { + assert(phase() == COLLECT_PHASE); + addValue(x); + } - public int getInt() { - return getValue(); - } - /** Return the sum of all values in this band. */ - public int getIntTotal() { - assert(phase() == DISBURSE_PHASE); - // assert that this is the whole pass; no other reads allowed - assert(valuesRemainingForDebug() == length()); - int total = 0; - for (int k = length(); k > 0; k--) { - total += getInt(); - } - resetForSecondPass(); - return total; - } - /** Return the occurrence count of a specific value in this band. */ - public int getIntCount(int value) { - assert(phase() == DISBURSE_PHASE); - // assert that this is the whole pass; no other reads allowed - assert(valuesRemainingForDebug() == length()); - int total = 0; - for (int k = length(); k > 0; k--) { - if (getInt() == value) { - total += 1; - } - } - resetForSecondPass(); - return total; - } + public int getInt() { + return getValue(); + } + /** Return the sum of all values in this band. */ + public int getIntTotal() { + assert(phase() == DISBURSE_PHASE); + // assert that this is the whole pass; no other reads allowed + assert(valuesRemainingForDebug() == length()); + int total = 0; + for (int k = length(); k > 0; k--) { + total += getInt(); + } + resetForSecondPass(); + return total; + } + /** Return the occurrence count of a specific value in this band. */ + public int getIntCount(int value) { + assert(phase() == DISBURSE_PHASE); + // assert that this is the whole pass; no other reads allowed + assert(valuesRemainingForDebug() == length()); + int total = 0; + for (int k = length(); k > 0; k--) { + if (getInt() == value) { + total += 1; + } + } + resetForSecondPass(); + return total; + } } static int getIntTotal(int[] values) { - int total = 0; - for (int i = 0; i < values.length; i++) { - total += values[i]; - } - return total; + int total = 0; + for (int i = 0; i < values.length; i++) { + total += values[i]; + } + return total; } class CPRefBand extends ValueBand { - Index index; - boolean nullOK; + Index index; + boolean nullOK; - public CPRefBand(String name, Coding regularCoding, byte cpTag, boolean nullOK) { - super(name, regularCoding); - this.nullOK = nullOK; - if (cpTag != CONSTANT_None) - setBandIndex(this, cpTag); - } - public CPRefBand(String name, Coding regularCoding, byte cpTag) { - this(name, regularCoding, cpTag, false); - } - public CPRefBand(String name, Coding regularCoding, Object undef) { - this(name, regularCoding, CONSTANT_None, false); - } + public CPRefBand(String name, Coding regularCoding, byte cpTag, boolean nullOK) { + super(name, regularCoding); + this.nullOK = nullOK; + if (cpTag != CONSTANT_None) + setBandIndex(this, cpTag); + } + public CPRefBand(String name, Coding regularCoding, byte cpTag) { + this(name, regularCoding, cpTag, false); + } + public CPRefBand(String name, Coding regularCoding, Object undef) { + this(name, regularCoding, CONSTANT_None, false); + } - public void setIndex(Index index) { - this.index = index; - } + public void setIndex(Index index) { + this.index = index; + } - protected void readDataFrom(InputStream in) throws IOException { - super.readDataFrom(in); - assert(assertValidCPRefs(this)); - } + protected void readDataFrom(InputStream in) throws IOException { + super.readDataFrom(in); + assert(assertValidCPRefs(this)); + } - /** Write a constant pool reference. */ - public void putRef(Entry e) { - assert(index != null); - addValue(encodeRefOrNull(e, index)); - } - public void putRef(Entry e, Index index) { - assert(this.index == null); - addValue(encodeRefOrNull(e, index)); - } - public void putRef(Entry e, byte cptag) { - putRef(e, getCPIndex(cptag)); - } + /** Write a constant pool reference. */ + public void putRef(Entry e) { + addValue(encodeRefOrNull(e, index)); + } + public void putRef(Entry e, Index index) { + assert(this.index == null); + addValue(encodeRefOrNull(e, index)); + } + public void putRef(Entry e, byte cptag) { + putRef(e, getCPIndex(cptag)); + } - public Entry getRef() { - if (index == null) Utils.log.warning("No index for "+this); - assert(index != null); - return decodeRefOrNull(getValue(), index); - } - public Entry getRef(Index index) { - assert(this.index == null); - return decodeRefOrNull(getValue(), index); - } - public Entry getRef(byte cptag) { - return getRef(getCPIndex(cptag)); - } + public Entry getRef() { + if (index == null) Utils.log.warning("No index for "+this); + assert(index != null); + return decodeRefOrNull(getValue(), index); + } + public Entry getRef(Index index) { + assert(this.index == null); + return decodeRefOrNull(getValue(), index); + } + public Entry getRef(byte cptag) { + return getRef(getCPIndex(cptag)); + } - private int encodeRefOrNull(Entry e, Index index) { - int nonNullCode; // NNC is the coding which assumes nulls are rare - if (e == null) { - nonNullCode = -1; // negative values are rare - } else { - nonNullCode = encodeRef(e, index); - } - // If nulls are expected, increment, to make -1 code turn to 0. - return (nullOK ? 1 : 0) + nonNullCode; - } - private Entry decodeRefOrNull(int code, Index index) { - // Inverse to encodeRefOrNull... - int nonNullCode = code - (nullOK ? 1 : 0); - if (nonNullCode == -1) { - return null; - } else { - return decodeRef(nonNullCode, index); - } - } + private int encodeRefOrNull(Entry e, Index index) { + int nonNullCode; // NNC is the coding which assumes nulls are rare + if (e == null) { + nonNullCode = -1; // negative values are rare + } else { + nonNullCode = encodeRef(e, index); + } + // If nulls are expected, increment, to make -1 code turn to 0. + return (nullOK ? 1 : 0) + nonNullCode; + } + private Entry decodeRefOrNull(int code, Index index) { + // Inverse to encodeRefOrNull... + int nonNullCode = code - (nullOK ? 1 : 0); + if (nonNullCode == -1) { + return null; + } else { + return decodeRef(nonNullCode, index); + } + } } // Bootstrap support for CPRefBands. These are needed to record @@ -1039,51 +1037,53 @@ class BandStructure implements Constants int encodeRef(Entry e, Index ix) { - int coding = ix.indexOf(e); - if (verbose > 2) - Utils.log.fine("putRef "+coding+" => "+e); - return coding; + if (ix == null) + throw new RuntimeException("null index for " + e.stringValue()); + int coding = ix.indexOf(e); + if (verbose > 2) + Utils.log.fine("putRef "+coding+" => "+e); + return coding; } Entry decodeRef(int n, Index ix) { - if (n < 0 || n >= ix.size()) - Utils.log.warning("decoding bad ref "+n+" in "+ix); - Entry e = ix.getEntry(n); - if (verbose > 2) - Utils.log.fine("getRef "+n+" => "+e); - return e; + if (n < 0 || n >= ix.size()) + Utils.log.warning("decoding bad ref "+n+" in "+ix); + Entry e = ix.getEntry(n); + if (verbose > 2) + Utils.log.fine("getRef "+n+" => "+e); + return e; } private CodingChooser codingChooser; protected CodingChooser getCodingChooser() { - if (codingChooser == null) { - codingChooser = new CodingChooser(effort, basicCodings); - if (codingChooser.stress != null - && this instanceof PackageWriter) { - // Twist the random state based on my first file. - // This sends each segment off in a different direction. - List classes = ((PackageWriter)this).pkg.classes; - if (!classes.isEmpty()) { - Package.Class cls = (Package.Class) classes.get(0); - codingChooser.addStressSeed(cls.getName().hashCode()); - } - } - } - return codingChooser; + if (codingChooser == null) { + codingChooser = new CodingChooser(effort, basicCodings); + if (codingChooser.stress != null + && this instanceof PackageWriter) { + // Twist the random state based on my first file. + // This sends each segment off in a different direction. + List classes = ((PackageWriter)this).pkg.classes; + if (!classes.isEmpty()) { + Package.Class cls = (Package.Class) classes.get(0); + codingChooser.addStressSeed(cls.getName().hashCode()); + } + } + } + return codingChooser; } public CodingMethod chooseCoding(int[] values, int start, int end, - Coding regular, String bandName, - int[] sizes) { - assert(optVaryCodings); - if (effort <= MIN_EFFORT) { - return regular; - } - CodingChooser cc = getCodingChooser(); - if (verbose > 1 || cc.verbose > 1) { - Utils.log.fine("--- chooseCoding "+bandName); - } - return cc.choose(values, start, end, regular, sizes); + Coding regular, String bandName, + int[] sizes) { + assert(optVaryCodings); + if (effort <= MIN_EFFORT) { + return regular; + } + CodingChooser cc = getCodingChooser(); + if (verbose > 1 || cc.verbose > 1) { + Utils.log.fine("--- chooseCoding "+bandName); + } + return cc.choose(values, start, end, regular, sizes); } static final byte[] defaultMetaCoding = { _meta_default }; @@ -1108,201 +1108,201 @@ class BandStructure implements Constants // Result is in [0..255] if XB was successfully extracted, else -1. // See section "Coding Specifier Meta-Encoding" in the JSR 200 spec. protected static int decodeEscapeValue(int X, Coding regularCoding) { - // The first value in a band is always coded with the default coding D. - // If this first value X is an escape value, it actually represents the - // first (and perhaps only) byte of a meta-coding. - // Result is in [0..255] if XB was successfully extracted, else -1. - if (regularCoding.B() == 1 || regularCoding.L() == 0) - return -1; // degenerate regular coding (BYTE1) - if (regularCoding.S() != 0) { - if (-256 <= X && X <= -1 && regularCoding.min() <= -256) { - int XB = -1-X; - assert(XB >= 0 && XB < 256); - return XB; - } - } else { - int L = regularCoding.L(); - if (L <= X && X <= L+255 && regularCoding.max() >= L+255) { - int XB = X-L; - assert(XB >= 0 && XB < 256); - return XB; - } - } - return -1; // negative value for failure + // The first value in a band is always coded with the default coding D. + // If this first value X is an escape value, it actually represents the + // first (and perhaps only) byte of a meta-coding. + // Result is in [0..255] if XB was successfully extracted, else -1. + if (regularCoding.B() == 1 || regularCoding.L() == 0) + return -1; // degenerate regular coding (BYTE1) + if (regularCoding.S() != 0) { + if (-256 <= X && X <= -1 && regularCoding.min() <= -256) { + int XB = -1-X; + assert(XB >= 0 && XB < 256); + return XB; + } + } else { + int L = regularCoding.L(); + if (L <= X && X <= L+255 && regularCoding.max() >= L+255) { + int XB = X-L; + assert(XB >= 0 && XB < 256); + return XB; + } + } + return -1; // negative value for failure } // Inverse to decodeEscapeValue(). protected static int encodeEscapeValue(int XB, Coding regularCoding) { - assert(XB >= 0 && XB < 256); - assert(regularCoding.B() > 1 && regularCoding.L() > 0); - int X; - if (regularCoding.S() != 0) { - assert(regularCoding.min() <= -256); - X = -1-XB; - } else { - int L = regularCoding.L(); - assert(regularCoding.max() >= L+255); - X = XB+L; - } - assert(decodeEscapeValue(X, regularCoding) == XB) - : (regularCoding+" XB="+XB+" X="+X); - return X; + assert(XB >= 0 && XB < 256); + assert(regularCoding.B() > 1 && regularCoding.L() > 0); + int X; + if (regularCoding.S() != 0) { + assert(regularCoding.min() <= -256); + X = -1-XB; + } else { + int L = regularCoding.L(); + assert(regularCoding.max() >= L+255); + X = XB+L; + } + assert(decodeEscapeValue(X, regularCoding) == XB) + : (regularCoding+" XB="+XB+" X="+X); + return X; } static { - boolean checkXB = false; - assert(checkXB = true); - if (checkXB) { - for (int i = 0; i < basicCodings.length; i++) { - Coding D = basicCodings[i]; - if (D == null) continue; - if (D.B() == 1) continue; - if (D.L() == 0) continue; - for (int XB = 0; XB <= 255; XB++) { - // The following exercises decodeEscapeValue also: - encodeEscapeValue(XB, D); - } - } - } + boolean checkXB = false; + assert(checkXB = true); + if (checkXB) { + for (int i = 0; i < basicCodings.length; i++) { + Coding D = basicCodings[i]; + if (D == null) continue; + if (D.B() == 1) continue; + if (D.L() == 0) continue; + for (int XB = 0; XB <= 255; XB++) { + // The following exercises decodeEscapeValue also: + encodeEscapeValue(XB, D); + } + } + } } class MultiBand extends Band { - MultiBand(String name, Coding regularCoding) { - super(name, regularCoding); - } + MultiBand(String name, Coding regularCoding) { + super(name, regularCoding); + } - public Band init() { - super.init(); - // This is all just to keep the asserts happy: - setCapacity(0); - if (phase() == EXPECT_PHASE) { - // Fast forward: - setPhase(READ_PHASE); - setPhase(DISBURSE_PHASE); - } - return this; - } + public Band init() { + super.init(); + // This is all just to keep the asserts happy: + setCapacity(0); + if (phase() == EXPECT_PHASE) { + // Fast forward: + setPhase(READ_PHASE); + setPhase(DISBURSE_PHASE); + } + return this; + } - Band[] bands = new Band[10]; - int bandCount = 0; + Band[] bands = new Band[10]; + int bandCount = 0; - int size() { - return bandCount; - } - Band get(int i) { - assert(i < bandCount); - return bands[i]; - } - Band[] toArray() { - return (Band[]) realloc(bands, bandCount); - } + int size() { + return bandCount; + } + Band get(int i) { + assert(i < bandCount); + return bands[i]; + } + Band[] toArray() { + return (Band[]) realloc(bands, bandCount); + } - void add(Band b) { - assert(bandCount == 0 || notePrevForAssert(b, bands[bandCount-1])); - if (bandCount == bands.length) { - bands = (Band[]) realloc(bands); - } - bands[bandCount++] = b; - } + void add(Band b) { + assert(bandCount == 0 || notePrevForAssert(b, bands[bandCount-1])); + if (bandCount == bands.length) { + bands = (Band[]) realloc(bands); + } + bands[bandCount++] = b; + } - ByteBand newByteBand(String name) { - ByteBand b = new ByteBand(name); - b.init(); add(b); - return b; - } - IntBand newIntBand(String name) { - IntBand b = new IntBand(name, regularCoding); - b.init(); add(b); - return b; - } - IntBand newIntBand(String name, Coding regularCoding) { - IntBand b = new IntBand(name, regularCoding); - b.init(); add(b); - return b; - } - MultiBand newMultiBand(String name, Coding regularCoding) { - MultiBand b = new MultiBand(name, regularCoding); - b.init(); add(b); - return b; - } - CPRefBand newCPRefBand(String name, byte cpTag) { - CPRefBand b = new CPRefBand(name, regularCoding, cpTag); - b.init(); add(b); - return b; - } - CPRefBand newCPRefBand(String name, Coding regularCoding, - byte cpTag) { - CPRefBand b = new CPRefBand(name, regularCoding, cpTag); - b.init(); add(b); - return b; - } - CPRefBand newCPRefBand(String name, Coding regularCoding, - byte cpTag, boolean nullOK) { - CPRefBand b = new CPRefBand(name, regularCoding, cpTag, nullOK); - b.init(); add(b); - return b; - } + ByteBand newByteBand(String name) { + ByteBand b = new ByteBand(name); + b.init(); add(b); + return b; + } + IntBand newIntBand(String name) { + IntBand b = new IntBand(name, regularCoding); + b.init(); add(b); + return b; + } + IntBand newIntBand(String name, Coding regularCoding) { + IntBand b = new IntBand(name, regularCoding); + b.init(); add(b); + return b; + } + MultiBand newMultiBand(String name, Coding regularCoding) { + MultiBand b = new MultiBand(name, regularCoding); + b.init(); add(b); + return b; + } + CPRefBand newCPRefBand(String name, byte cpTag) { + CPRefBand b = new CPRefBand(name, regularCoding, cpTag); + b.init(); add(b); + return b; + } + CPRefBand newCPRefBand(String name, Coding regularCoding, + byte cpTag) { + CPRefBand b = new CPRefBand(name, regularCoding, cpTag); + b.init(); add(b); + return b; + } + CPRefBand newCPRefBand(String name, Coding regularCoding, + byte cpTag, boolean nullOK) { + CPRefBand b = new CPRefBand(name, regularCoding, cpTag, nullOK); + b.init(); add(b); + return b; + } - int bandCount() { return bandCount; } + int bandCount() { return bandCount; } - private int cap = -1; - public int capacity() { return cap; } - public void setCapacity(int cap) { this.cap = cap; } + private int cap = -1; + public int capacity() { return cap; } + public void setCapacity(int cap) { this.cap = cap; } - public int length() { return 0; } - public int valuesRemainingForDebug() { return 0; } + public int length() { return 0; } + public int valuesRemainingForDebug() { return 0; } - protected void chooseBandCodings() throws IOException { - // coding decision pass - for (int i = 0; i < bandCount; i++) { - Band b = bands[i]; - b.chooseBandCodings(); - } - } + protected void chooseBandCodings() throws IOException { + // coding decision pass + for (int i = 0; i < bandCount; i++) { + Band b = bands[i]; + b.chooseBandCodings(); + } + } - protected long computeOutputSize() { - // coding decision pass - long sum = 0; - for (int i = 0; i < bandCount; i++) { - Band b = bands[i]; - long bsize = b.outputSize(); - assert(bsize >= 0) : b; - sum += bsize; - } - // do not cache - return sum; - } + protected long computeOutputSize() { + // coding decision pass + long sum = 0; + for (int i = 0; i < bandCount; i++) { + Band b = bands[i]; + long bsize = b.outputSize(); + assert(bsize >= 0) : b; + sum += bsize; + } + // do not cache + return sum; + } - protected void writeDataTo(OutputStream out) throws IOException { - long preCount = 0; - if (outputCounter != null) preCount = outputCounter.getCount(); - for (int i = 0; i < bandCount; i++) { - Band b = bands[i]; - b.writeTo(out); - if (outputCounter != null) { - long postCount = outputCounter.getCount(); - long len = postCount - preCount; - preCount = postCount; - if ((verbose > 0 && len > 0) || verbose > 1) { - Utils.log.info(" ...wrote "+len+" bytes from "+b); - } - } - } - } + protected void writeDataTo(OutputStream out) throws IOException { + long preCount = 0; + if (outputCounter != null) preCount = outputCounter.getCount(); + for (int i = 0; i < bandCount; i++) { + Band b = bands[i]; + b.writeTo(out); + if (outputCounter != null) { + long postCount = outputCounter.getCount(); + long len = postCount - preCount; + preCount = postCount; + if ((verbose > 0 && len > 0) || verbose > 1) { + Utils.log.info(" ...wrote "+len+" bytes from "+b); + } + } + } + } - protected void readDataFrom(InputStream in) throws IOException { - assert(false); // not called? - for (int i = 0; i < bandCount; i++) { - Band b = bands[i]; - b.readFrom(in); - if ((verbose > 0 && b.length() > 0) || verbose > 1) { - Utils.log.info(" ...read "+b); - } - } - } + protected void readDataFrom(InputStream in) throws IOException { + assert(false); // not called? + for (int i = 0; i < bandCount; i++) { + Band b = bands[i]; + b.readFrom(in); + if ((verbose > 0 && b.length() > 0) || verbose > 1) { + Utils.log.info(" ...read "+b); + } + } + } - public String toString() { - return "{"+bandCount()+" bands: "+super.toString()+"}"; - } + public String toString() { + return "{"+bandCount()+" bands: "+super.toString()+"}"; + } } /** @@ -1310,42 +1310,42 @@ class BandStructure implements Constants */ private static class ByteCounter extends FilterOutputStream { - // (should go public under the name CountingOutputStream?) + // (should go public under the name CountingOutputStream?) - private long count; + private long count; - public ByteCounter(OutputStream out) { - super(out); - } + public ByteCounter(OutputStream out) { + super(out); + } - public long getCount() { return count; } - public void setCount(long c) { count = c; } + public long getCount() { return count; } + public void setCount(long c) { count = c; } - public void write(int b) throws IOException { - count++; - if (out != null) out.write(b); - } - public void write(byte b[], int off, int len) throws IOException { - count += len; - if (out != null) out.write(b, off, len); - } - public String toString() { - return String.valueOf(getCount()); - } + public void write(int b) throws IOException { + count++; + if (out != null) out.write(b); + } + public void write(byte b[], int off, int len) throws IOException { + count += len; + if (out != null) out.write(b, off, len); + } + public String toString() { + return String.valueOf(getCount()); + } } ByteCounter outputCounter; void writeAllBandsTo(OutputStream out) throws IOException { - // Wrap a byte-counter around the output stream. - outputCounter = new ByteCounter(out); - out = outputCounter; - all_bands.writeTo(out); - if (verbose > 0) { - long nbytes = outputCounter.getCount(); - Utils.log.info("Wrote total of "+nbytes+" bytes."); - assert(nbytes == archiveSize0+archiveSize1); - } - outputCounter = null; + // Wrap a byte-counter around the output stream. + outputCounter = new ByteCounter(out); + out = outputCounter; + all_bands.writeTo(out); + if (verbose > 0) { + long nbytes = outputCounter.getCount(); + Utils.log.info("Wrote total of "+nbytes+" bytes."); + assert(nbytes == archiveSize0+archiveSize1); + } + outputCounter = null; } // random AO_XXX bits, decoded from the archive header @@ -1366,7 +1366,7 @@ class BandStructure implements Constants static final int AH_SPECIAL_FORMAT_LEN = 2; // layouts/band-headers static final int AH_CP_NUMBER_LEN = 4; // int/float/long/double static final int AH_LENGTH_MIN = AH_LENGTH - -(AH_SPECIAL_FORMAT_LEN+AH_FILE_HEADER_LEN+AH_CP_NUMBER_LEN); + -(AH_SPECIAL_FORMAT_LEN+AH_FILE_HEADER_LEN+AH_CP_NUMBER_LEN); // Common structure of attribute band groups: static final int AB_FLAGS_HI = 0; @@ -1376,22 +1376,22 @@ class BandStructure implements Constants static final int AB_ATTR_CALLS = 4; static IntBand getAttrBand(MultiBand xxx_attr_bands, int which) { - IntBand b = (IntBand) xxx_attr_bands.get(which); - switch (which) { - case AB_FLAGS_HI: - assert(b.name().endsWith("_flags_hi")); break; - case AB_FLAGS_LO: - assert(b.name().endsWith("_flags_lo")); break; - case AB_ATTR_COUNT: - assert(b.name().endsWith("_attr_count")); break; - case AB_ATTR_INDEXES: - assert(b.name().endsWith("_attr_indexes")); break; - case AB_ATTR_CALLS: - assert(b.name().endsWith("_attr_calls")); break; - default: - assert(false); break; - } - return b; + IntBand b = (IntBand) xxx_attr_bands.get(which); + switch (which) { + case AB_FLAGS_HI: + assert(b.name().endsWith("_flags_hi")); break; + case AB_FLAGS_LO: + assert(b.name().endsWith("_flags_lo")); break; + case AB_ATTR_COUNT: + assert(b.name().endsWith("_attr_count")); break; + case AB_ATTR_INDEXES: + assert(b.name().endsWith("_attr_indexes")); break; + case AB_ATTR_CALLS: + assert(b.name().endsWith("_attr_calls")); break; + default: + assert(false); break; + } + return b; } static private final boolean NULL_IS_OK = true; @@ -1602,55 +1602,55 @@ class BandStructure implements Constants /** Given CP indexes, distribute tag-specific indexes to bands. */ protected void setBandIndexes() { - // Handle prior calls to setBandIndex: - for (Iterator i = needPredefIndex.iterator(); i.hasNext(); ) { - Object[] need = (Object[]) i.next(); - CPRefBand b = (CPRefBand) need[0]; - Byte which = (Byte) need[1]; - b.setIndex(getCPIndex(which.byteValue())); - } - needPredefIndex = null; // no more predefs + // Handle prior calls to setBandIndex: + for (Iterator i = needPredefIndex.iterator(); i.hasNext(); ) { + Object[] need = (Object[]) i.next(); + CPRefBand b = (CPRefBand) need[0]; + Byte which = (Byte) need[1]; + b.setIndex(getCPIndex(which.byteValue())); + } + needPredefIndex = null; // no more predefs - if (verbose > 3) { - printCDecl(all_bands); - } + if (verbose > 3) { + printCDecl(all_bands); + } } protected void setBandIndex(CPRefBand b, byte which) { - Object[] need = { b, new Byte(which) }; - if (which == CONSTANT_Literal) { - // I.e., attribute layouts KQ (no null) or KQN (null ok). - allKQBands.add(b); - } else if (needPredefIndex != null) { - needPredefIndex.add(need); - } else { - // Not in predefinition mode; getCPIndex now works. - b.setIndex(getCPIndex(which)); - } + Object[] need = { b, new Byte(which) }; + if (which == CONSTANT_Literal) { + // I.e., attribute layouts KQ (no null) or KQN (null ok). + allKQBands.add(b); + } else if (needPredefIndex != null) { + needPredefIndex.add(need); + } else { + // Not in predefinition mode; getCPIndex now works. + b.setIndex(getCPIndex(which)); + } } protected void setConstantValueIndex(Class.Field f) { - Index ix = null; - if (f != null) { - byte tag = f.getLiteralTag(); - ix = getCPIndex(tag); - if (verbose > 2) - Utils.log.fine("setConstantValueIndex "+f+" "+ConstantPool.tagName(tag)+" => "+ix); - assert(ix != null); - } - // Typically, allKQBands is the singleton of field_ConstantValue_KQ. - for (Iterator i = allKQBands.iterator(); i.hasNext(); ) { - CPRefBand xxx_KQ = (CPRefBand) i.next(); - xxx_KQ.setIndex(ix); - } + Index ix = null; + if (f != null) { + byte tag = f.getLiteralTag(); + ix = getCPIndex(tag); + if (verbose > 2) + Utils.log.fine("setConstantValueIndex "+f+" "+ConstantPool.tagName(tag)+" => "+ix); + assert(ix != null); + } + // Typically, allKQBands is the singleton of field_ConstantValue_KQ. + for (Iterator i = allKQBands.iterator(); i.hasNext(); ) { + CPRefBand xxx_KQ = (CPRefBand) i.next(); + xxx_KQ.setIndex(ix); + } } // Table of bands which contain metadata. protected MultiBand[] metadataBands = new MultiBand[ATTR_CONTEXT_LIMIT]; { - metadataBands[ATTR_CONTEXT_CLASS] = class_metadata_bands; - metadataBands[ATTR_CONTEXT_FIELD] = field_metadata_bands; - metadataBands[ATTR_CONTEXT_METHOD] = method_metadata_bands; + metadataBands[ATTR_CONTEXT_CLASS] = class_metadata_bands; + metadataBands[ATTR_CONTEXT_FIELD] = field_metadata_bands; + metadataBands[ATTR_CONTEXT_METHOD] = method_metadata_bands; } // Attribute layouts. @@ -1686,660 +1686,660 @@ class BandStructure implements Constants // Mapping from attribute index (<32 are flag bits) to attributes. protected ArrayList[] attrDefs = new ArrayList[ATTR_CONTEXT_LIMIT]; { - for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { - assert(attrIndexLimit[i] == 0); - attrIndexLimit[i] = 32; // just for the sake of predefs. - attrDefs[i] = new ArrayList(Collections.nCopies(attrIndexLimit[i], null)); - } + for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { + assert(attrIndexLimit[i] == 0); + attrIndexLimit[i] = 32; // just for the sake of predefs. + attrDefs[i] = new ArrayList(Collections.nCopies(attrIndexLimit[i], null)); + } - // Add predefined attribute definitions: - attrInnerClassesEmpty = - predefineAttribute(CLASS_ATTR_InnerClasses, ATTR_CONTEXT_CLASS, null, - "InnerClasses", ""); - assert(attrInnerClassesEmpty == Package.attrInnerClassesEmpty); - predefineAttribute(CLASS_ATTR_SourceFile, ATTR_CONTEXT_CLASS, - new Band[] { class_SourceFile_RUN }, - "SourceFile", "RUNH"); - predefineAttribute(CLASS_ATTR_EnclosingMethod, ATTR_CONTEXT_CLASS, - new Band[] { - class_EnclosingMethod_RC, - class_EnclosingMethod_RDN - }, - "EnclosingMethod", "RCHRDNH"); - attrClassFileVersion = - predefineAttribute(CLASS_ATTR_ClassFile_version, ATTR_CONTEXT_CLASS, - new Band[] { - class_ClassFile_version_minor_H, - class_ClassFile_version_major_H - }, - ".ClassFile.version", "HH"); - predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_CLASS, - new Band[] { class_Signature_RS }, - "Signature", "RSH"); - predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_CLASS, null, - "Deprecated", ""); - //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_CLASS, null, - // "Synthetic", ""); - predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_CLASS, null, - ".Overflow", ""); - attrConstantValue = - predefineAttribute(FIELD_ATTR_ConstantValue, ATTR_CONTEXT_FIELD, - new Band[] { field_ConstantValue_KQ }, - "ConstantValue", "KQH"); - predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_FIELD, - new Band[] { field_Signature_RS }, - "Signature", "RSH"); - predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_FIELD, null, - "Deprecated", ""); - //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_FIELD, null, - // "Synthetic", ""); - predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_FIELD, null, - ".Overflow", ""); - attrCodeEmpty = - predefineAttribute(METHOD_ATTR_Code, ATTR_CONTEXT_METHOD, null, - "Code", ""); - predefineAttribute(METHOD_ATTR_Exceptions, ATTR_CONTEXT_METHOD, - new Band[] { - method_Exceptions_N, - method_Exceptions_RC - }, - "Exceptions", "NH[RCH]"); - assert(attrCodeEmpty == Package.attrCodeEmpty); - predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_METHOD, - new Band[] { method_Signature_RS }, - "Signature", "RSH"); - predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_METHOD, null, - "Deprecated", ""); - //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_METHOD, null, - // "Synthetic", ""); - predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_METHOD, null, - ".Overflow", ""); + // Add predefined attribute definitions: + attrInnerClassesEmpty = + predefineAttribute(CLASS_ATTR_InnerClasses, ATTR_CONTEXT_CLASS, null, + "InnerClasses", ""); + assert(attrInnerClassesEmpty == Package.attrInnerClassesEmpty); + predefineAttribute(CLASS_ATTR_SourceFile, ATTR_CONTEXT_CLASS, + new Band[] { class_SourceFile_RUN }, + "SourceFile", "RUNH"); + predefineAttribute(CLASS_ATTR_EnclosingMethod, ATTR_CONTEXT_CLASS, + new Band[] { + class_EnclosingMethod_RC, + class_EnclosingMethod_RDN + }, + "EnclosingMethod", "RCHRDNH"); + attrClassFileVersion = + predefineAttribute(CLASS_ATTR_ClassFile_version, ATTR_CONTEXT_CLASS, + new Band[] { + class_ClassFile_version_minor_H, + class_ClassFile_version_major_H + }, + ".ClassFile.version", "HH"); + predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_CLASS, + new Band[] { class_Signature_RS }, + "Signature", "RSH"); + predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_CLASS, null, + "Deprecated", ""); + //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_CLASS, null, + // "Synthetic", ""); + predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_CLASS, null, + ".Overflow", ""); + attrConstantValue = + predefineAttribute(FIELD_ATTR_ConstantValue, ATTR_CONTEXT_FIELD, + new Band[] { field_ConstantValue_KQ }, + "ConstantValue", "KQH"); + predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_FIELD, + new Band[] { field_Signature_RS }, + "Signature", "RSH"); + predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_FIELD, null, + "Deprecated", ""); + //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_FIELD, null, + // "Synthetic", ""); + predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_FIELD, null, + ".Overflow", ""); + attrCodeEmpty = + predefineAttribute(METHOD_ATTR_Code, ATTR_CONTEXT_METHOD, null, + "Code", ""); + predefineAttribute(METHOD_ATTR_Exceptions, ATTR_CONTEXT_METHOD, + new Band[] { + method_Exceptions_N, + method_Exceptions_RC + }, + "Exceptions", "NH[RCH]"); + assert(attrCodeEmpty == Package.attrCodeEmpty); + predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_METHOD, + new Band[] { method_Signature_RS }, + "Signature", "RSH"); + predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_METHOD, null, + "Deprecated", ""); + //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_METHOD, null, + // "Synthetic", ""); + predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_METHOD, null, + ".Overflow", ""); - for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) { - MultiBand xxx_metadata_bands = metadataBands[ctype]; - if (xxx_metadata_bands == null) - continue; // no code attrs + for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) { + MultiBand xxx_metadata_bands = metadataBands[ctype]; + if (xxx_metadata_bands == null) + continue; // no code attrs - // These arguments cause the bands to be built - // automatically for this complicated layout: - predefineAttribute(X_ATTR_RuntimeVisibleAnnotations, - ATTR_CONTEXT_NAME[ctype]+"_RVA_", - xxx_metadata_bands, - Attribute.lookup(null, ctype, - "RuntimeVisibleAnnotations")); - predefineAttribute(X_ATTR_RuntimeInvisibleAnnotations, - ATTR_CONTEXT_NAME[ctype]+"_RIA_", - xxx_metadata_bands, - Attribute.lookup(null, ctype, - "RuntimeInvisibleAnnotations")); - if (ctype != ATTR_CONTEXT_METHOD) - continue; + // These arguments cause the bands to be built + // automatically for this complicated layout: + predefineAttribute(X_ATTR_RuntimeVisibleAnnotations, + ATTR_CONTEXT_NAME[ctype]+"_RVA_", + xxx_metadata_bands, + Attribute.lookup(null, ctype, + "RuntimeVisibleAnnotations")); + predefineAttribute(X_ATTR_RuntimeInvisibleAnnotations, + ATTR_CONTEXT_NAME[ctype]+"_RIA_", + xxx_metadata_bands, + Attribute.lookup(null, ctype, + "RuntimeInvisibleAnnotations")); + if (ctype != ATTR_CONTEXT_METHOD) + continue; - predefineAttribute(METHOD_ATTR_RuntimeVisibleParameterAnnotations, - "method_RVPA_", xxx_metadata_bands, - Attribute.lookup(null, ctype, - "RuntimeVisibleParameterAnnotations")); - predefineAttribute(METHOD_ATTR_RuntimeInvisibleParameterAnnotations, - "method_RIPA_", xxx_metadata_bands, - Attribute.lookup(null, ctype, - "RuntimeInvisibleParameterAnnotations")); - predefineAttribute(METHOD_ATTR_AnnotationDefault, - "method_AD_", xxx_metadata_bands, - Attribute.lookup(null, ctype, - "AnnotationDefault")); - } + predefineAttribute(METHOD_ATTR_RuntimeVisibleParameterAnnotations, + "method_RVPA_", xxx_metadata_bands, + Attribute.lookup(null, ctype, + "RuntimeVisibleParameterAnnotations")); + predefineAttribute(METHOD_ATTR_RuntimeInvisibleParameterAnnotations, + "method_RIPA_", xxx_metadata_bands, + Attribute.lookup(null, ctype, + "RuntimeInvisibleParameterAnnotations")); + predefineAttribute(METHOD_ATTR_AnnotationDefault, + "method_AD_", xxx_metadata_bands, + Attribute.lookup(null, ctype, + "AnnotationDefault")); + } - Attribute.Layout stackMapDef = Attribute.lookup(null, ATTR_CONTEXT_CODE, "StackMapTable").layout(); - predefineAttribute(CODE_ATTR_StackMapTable, ATTR_CONTEXT_CODE, - stackmap_bands.toArray(), - stackMapDef.name(), stackMapDef.layout()); + Attribute.Layout stackMapDef = Attribute.lookup(null, ATTR_CONTEXT_CODE, "StackMapTable").layout(); + predefineAttribute(CODE_ATTR_StackMapTable, ATTR_CONTEXT_CODE, + stackmap_bands.toArray(), + stackMapDef.name(), stackMapDef.layout()); - predefineAttribute(CODE_ATTR_LineNumberTable, ATTR_CONTEXT_CODE, - new Band[] { - code_LineNumberTable_N, - code_LineNumberTable_bci_P, - code_LineNumberTable_line - }, - "LineNumberTable", "NH[PHH]"); - predefineAttribute(CODE_ATTR_LocalVariableTable, ATTR_CONTEXT_CODE, - new Band[] { - code_LocalVariableTable_N, - code_LocalVariableTable_bci_P, - code_LocalVariableTable_span_O, - code_LocalVariableTable_name_RU, - code_LocalVariableTable_type_RS, - code_LocalVariableTable_slot - }, - "LocalVariableTable", "NH[PHOHRUHRSHH]"); - predefineAttribute(CODE_ATTR_LocalVariableTypeTable, ATTR_CONTEXT_CODE, - new Band[] { - code_LocalVariableTypeTable_N, - code_LocalVariableTypeTable_bci_P, - code_LocalVariableTypeTable_span_O, - code_LocalVariableTypeTable_name_RU, - code_LocalVariableTypeTable_type_RS, - code_LocalVariableTypeTable_slot - }, - "LocalVariableTypeTable", "NH[PHOHRUHRSHH]"); - predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_CODE, null, - ".Overflow", ""); + predefineAttribute(CODE_ATTR_LineNumberTable, ATTR_CONTEXT_CODE, + new Band[] { + code_LineNumberTable_N, + code_LineNumberTable_bci_P, + code_LineNumberTable_line + }, + "LineNumberTable", "NH[PHH]"); + predefineAttribute(CODE_ATTR_LocalVariableTable, ATTR_CONTEXT_CODE, + new Band[] { + code_LocalVariableTable_N, + code_LocalVariableTable_bci_P, + code_LocalVariableTable_span_O, + code_LocalVariableTable_name_RU, + code_LocalVariableTable_type_RS, + code_LocalVariableTable_slot + }, + "LocalVariableTable", "NH[PHOHRUHRSHH]"); + predefineAttribute(CODE_ATTR_LocalVariableTypeTable, ATTR_CONTEXT_CODE, + new Band[] { + code_LocalVariableTypeTable_N, + code_LocalVariableTypeTable_bci_P, + code_LocalVariableTypeTable_span_O, + code_LocalVariableTypeTable_name_RU, + code_LocalVariableTypeTable_type_RS, + code_LocalVariableTypeTable_slot + }, + "LocalVariableTypeTable", "NH[PHOHRUHRSHH]"); + predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_CODE, null, + ".Overflow", ""); - // Clear the record of having seen these definitions, - // so they may be redefined without error. - for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { - attrDefSeen[i] = 0; - } + // Clear the record of having seen these definitions, + // so they may be redefined without error. + for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { + attrDefSeen[i] = 0; + } - // Set up the special masks: - for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { - attrOverflowMask[i] = (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() < JAVA6_PACKAGE_MAJOR_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); + } } protected void initAttrIndexLimit() { - for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { - assert(attrIndexLimit[i] == 0); // decide on it now! - attrIndexLimit[i] = (haveFlagsHi(i)? 63: 32); - assert(attrDefs[i].size() == 32); // all predef indexes are <32 - int addMore = attrIndexLimit[i] - attrDefs[i].size(); - attrDefs[i].addAll(Collections.nCopies(addMore, null)); - } + for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { + assert(attrIndexLimit[i] == 0); // decide on it now! + attrIndexLimit[i] = (haveFlagsHi(i)? 63: 32); + assert(attrDefs[i].size() == 32); // all predef indexes are <32 + int addMore = attrIndexLimit[i] - attrDefs[i].size(); + attrDefs[i].addAll(Collections.nCopies(addMore, null)); + } } protected boolean haveFlagsHi(int ctype) { - int mask = 1<<(LG_AO_HAVE_XXX_FLAGS_HI+ctype); - switch (ctype) { - case ATTR_CONTEXT_CLASS: - assert(mask == AO_HAVE_CLASS_FLAGS_HI); break; - case ATTR_CONTEXT_FIELD: - assert(mask == AO_HAVE_FIELD_FLAGS_HI); break; - case ATTR_CONTEXT_METHOD: - assert(mask == AO_HAVE_METHOD_FLAGS_HI); break; - case ATTR_CONTEXT_CODE: - assert(mask == AO_HAVE_CODE_FLAGS_HI); break; - default: - assert(false); - } - return testBit(archiveOptions, mask); + int mask = 1<<(LG_AO_HAVE_XXX_FLAGS_HI+ctype); + switch (ctype) { + case ATTR_CONTEXT_CLASS: + assert(mask == AO_HAVE_CLASS_FLAGS_HI); break; + case ATTR_CONTEXT_FIELD: + assert(mask == AO_HAVE_FIELD_FLAGS_HI); break; + case ATTR_CONTEXT_METHOD: + assert(mask == AO_HAVE_METHOD_FLAGS_HI); break; + case ATTR_CONTEXT_CODE: + assert(mask == AO_HAVE_CODE_FLAGS_HI); break; + default: + assert(false); + } + return testBit(archiveOptions, mask); } protected ArrayList getPredefinedAttrs(int ctype) { - assert(attrIndexLimit[ctype] != 0); - ArrayList res = new ArrayList(attrIndexLimit[ctype]); - // Remove nulls and non-predefs. - for (int ai = 0; ai < attrIndexLimit[ctype]; ai++) { - if (testBit(attrDefSeen[ctype], 1L<= attrIndexLimit[ctype]) return false; - // If the bit is set, it was explicitly def'd. - if (testBit(attrDefSeen[ctype], 1L<= attrIndexLimit[ctype]) return false; + // If the bit is set, it was explicitly def'd. + if (testBit(attrDefSeen[ctype], 1L<> 8), (byte)minver, - (byte)(majver >> 8), (byte)majver - }; - return attrClassFileVersion.addContent(bytes); + byte[] bytes = { + (byte)(minver >> 8), (byte)minver, + (byte)(majver >> 8), (byte)majver + }; + return attrClassFileVersion.addContent(bytes); } protected short[] 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 }; + 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 }; } private boolean assertBandOKForElems(Band[] ab, Attribute.Layout.Element[] elems) { - for (int i = 0; i < elems.length; i++) { - assert(assertBandOKForElem(ab, elems[i])); - } - return true; + for (int i = 0; i < elems.length; i++) { + assert(assertBandOKForElem(ab, elems[i])); + } + return true; } private boolean assertBandOKForElem(Band[] ab, Attribute.Layout.Element e) { - Band b = null; - if (e.bandIndex != Attribute.NO_BAND_INDEX) - b = ab[e.bandIndex]; - Coding rc = UNSIGNED5; - boolean wantIntBand = true; - switch (e.kind) { - case Attribute.EK_INT: - if (e.flagTest(Attribute.EF_SIGN)) { - rc = SIGNED5; - } else if (e.len == 1) { - rc = BYTE1; - } - break; - case Attribute.EK_BCI: - if (!e.flagTest(Attribute.EF_DELTA)) { - rc = BCI5; - } else { - rc = BRANCH5; - } - break; - case Attribute.EK_BCO: - rc = BRANCH5; - break; - case Attribute.EK_FLAG: - if (e.len == 1) rc = BYTE1; - break; - case Attribute.EK_REPL: - if (e.len == 1) rc = BYTE1; - assertBandOKForElems(ab, e.body); - break; - case Attribute.EK_UN: - if (e.flagTest(Attribute.EF_SIGN)) { - rc = SIGNED5; - } else if (e.len == 1) { - rc = BYTE1; - } - assertBandOKForElems(ab, e.body); - break; - case Attribute.EK_CASE: - assert(b == null); - assertBandOKForElems(ab, e.body); - return true; // no direct band - case Attribute.EK_CALL: - assert(b == null); - return true; // no direct band - case Attribute.EK_CBLE: - assert(b == null); - assertBandOKForElems(ab, e.body); - return true; // no direct band - case Attribute.EK_REF: - wantIntBand = false; - assert(b instanceof CPRefBand); - assert(((CPRefBand)b).nullOK == e.flagTest(Attribute.EF_NULL)); - break; - default: assert(false); - } - assert(b.regularCoding == rc) - : (e+" // "+b); - if (wantIntBand) - assert(b instanceof IntBand); - return true; + Band b = null; + if (e.bandIndex != Attribute.NO_BAND_INDEX) + b = ab[e.bandIndex]; + Coding rc = UNSIGNED5; + boolean wantIntBand = true; + switch (e.kind) { + case Attribute.EK_INT: + if (e.flagTest(Attribute.EF_SIGN)) { + rc = SIGNED5; + } else if (e.len == 1) { + rc = BYTE1; + } + break; + case Attribute.EK_BCI: + if (!e.flagTest(Attribute.EF_DELTA)) { + rc = BCI5; + } else { + rc = BRANCH5; + } + break; + case Attribute.EK_BCO: + rc = BRANCH5; + break; + case Attribute.EK_FLAG: + if (e.len == 1) rc = BYTE1; + break; + case Attribute.EK_REPL: + if (e.len == 1) rc = BYTE1; + assertBandOKForElems(ab, e.body); + break; + case Attribute.EK_UN: + if (e.flagTest(Attribute.EF_SIGN)) { + rc = SIGNED5; + } else if (e.len == 1) { + rc = BYTE1; + } + assertBandOKForElems(ab, e.body); + break; + case Attribute.EK_CASE: + assert(b == null); + assertBandOKForElems(ab, e.body); + return true; // no direct band + case Attribute.EK_CALL: + assert(b == null); + return true; // no direct band + case Attribute.EK_CBLE: + assert(b == null); + assertBandOKForElems(ab, e.body); + return true; // no direct band + case Attribute.EK_REF: + wantIntBand = false; + assert(b instanceof CPRefBand); + assert(((CPRefBand)b).nullOK == e.flagTest(Attribute.EF_NULL)); + break; + default: assert(false); + } + assert(b.regularCoding == rc) + : (e+" // "+b); + if (wantIntBand) + assert(b instanceof IntBand); + return true; } private Attribute.Layout predefineAttribute(int index, int ctype, Band[] ab, - String name, String layout) { - // Use Attribute.find to get uniquification of layouts. - Attribute.Layout def = Attribute.find(ctype, name, layout).layout(); - //def.predef = true; - if (index >= 0) { - setAttributeLayoutIndex(def, index); - } - if (ab == null) { - ab = new Band[0]; - } - assert(attrBandTable.get(def) == null); // no redef - attrBandTable.put(def, ab); - assert(def.bandCount == ab.length) - : (def+" // "+Arrays.asList(ab)); - // Let's make sure the band types match: - assert(assertBandOKForElems(ab, def.elems)); - return def; + String name, String layout) { + // Use Attribute.find to get uniquification of layouts. + Attribute.Layout def = Attribute.find(ctype, name, layout).layout(); + //def.predef = true; + if (index >= 0) { + setAttributeLayoutIndex(def, index); + } + if (ab == null) { + ab = new Band[0]; + } + assert(attrBandTable.get(def) == null); // no redef + attrBandTable.put(def, ab); + assert(def.bandCount == ab.length) + : (def+" // "+Arrays.asList(ab)); + // Let's make sure the band types match: + assert(assertBandOKForElems(ab, def.elems)); + return def; } // This version takes bandPrefix/addHere instead of prebuilt Band[] ab. private Attribute.Layout predefineAttribute(int index, - String bandPrefix, MultiBand addHere, - Attribute attr) { - //Attribute.Layout def = Attribute.find(ctype, name, layout).layout(); - Attribute.Layout def = attr.layout(); - int ctype = def.ctype(); - return predefineAttribute(index, ctype, - makeNewAttributeBands(bandPrefix, def, - addHere), - def.name(), def.layout()); + String bandPrefix, MultiBand addHere, + Attribute attr) { + //Attribute.Layout def = Attribute.find(ctype, name, layout).layout(); + Attribute.Layout def = attr.layout(); + int ctype = def.ctype(); + return predefineAttribute(index, ctype, + makeNewAttributeBands(bandPrefix, def, + addHere), + def.name(), def.layout()); } private void undefineAttribute(int index, int ctype) { - if (verbose > 1) { - System.out.println("Removing predefined "+ATTR_CONTEXT_NAME[ctype]+ - " attribute on bit "+index); - } - List defList = attrDefs[ctype]; - Attribute.Layout def = (Attribute.Layout) defList.get(index); - assert(def != null); - defList.set(index, null); - attrIndexTable.put(def, null); - // Clear the def bit. (For predefs, it's already clear.) - assert(index < 64); - attrDefSeen[ctype] &= ~(1L< 1) { + System.out.println("Removing predefined "+ATTR_CONTEXT_NAME[ctype]+ + " attribute on bit "+index); + } + List defList = attrDefs[ctype]; + Attribute.Layout def = (Attribute.Layout) defList.get(index); + assert(def != null); + defList.set(index, null); + attrIndexTable.put(def, null); + // Clear the def bit. (For predefs, it's already clear.) + assert(index < 64); + attrDefSeen[ctype] &= ~(1L< 1) - Utils.log.fine("Making new bands for "+def); - Band[] newAB = makeNewAttributeBands(pfx, def, - xxx_attr_bands); - assert(newAB.length == def.bandCount); - Band[] prevAB = (Band[]) attrBandTable.put(def, newAB); - if (prevAB != null) { - // We won't be using these predefined bands. - for (int j = 0; j < prevAB.length; j++) { - prevAB[j].doneWithUnusedBand(); - } - } - } - } - //System.out.println(prevForAssertMap); + for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) { + String cname = ATTR_CONTEXT_NAME[ctype]; + MultiBand xxx_attr_bands = attrBands[ctype]; + long defSeen = attrDefSeen[ctype]; + // Note: attrDefSeen is always a subset of attrFlagMask. + assert((defSeen & ~attrFlagMask[ctype]) == 0); + for (int i = 0; i < attrDefs[ctype].size(); i++) { + Attribute.Layout def = (Attribute.Layout) + attrDefs[ctype].get(i); + if (def == null) continue; // unused flag bit + if (def.bandCount == 0) continue; // empty attr + if (i < attrIndexLimit[ctype] && !testBit(defSeen, 1L< 1) + Utils.log.fine("Making new bands for "+def); + Band[] newAB = makeNewAttributeBands(pfx, def, + xxx_attr_bands); + assert(newAB.length == def.bandCount); + Band[] prevAB = (Band[]) attrBandTable.put(def, newAB); + if (prevAB != null) { + // We won't be using these predefined bands. + for (int j = 0; j < prevAB.length; j++) { + prevAB[j].doneWithUnusedBand(); + } + } + } + } + //System.out.println(prevForAssertMap); } private Band[] makeNewAttributeBands(String pfx, Attribute.Layout def, - MultiBand addHere) { - int base = addHere.size(); - makeNewAttributeBands(pfx, def.elems, addHere); - int nb = addHere.size() - base; - Band[] newAB = new Band[nb]; - for (int i = 0; i < nb; i++) { - newAB[i] = addHere.get(base+i); - } - return newAB; + MultiBand addHere) { + int base = addHere.size(); + makeNewAttributeBands(pfx, def.elems, addHere); + int nb = addHere.size() - base; + Band[] newAB = new Band[nb]; + for (int i = 0; i < nb; i++) { + newAB[i] = addHere.get(base+i); + } + return newAB; } // Recursive helper, operates on a "body" or other sequence of elems: private void makeNewAttributeBands(String pfx, Attribute.Layout.Element[] elems, - MultiBand ab) { - for (int i = 0; i < elems.length; i++) { - Attribute.Layout.Element e = elems[i]; - String name = pfx+ab.size()+"_"+e.layout; - { - int tem; - if ((tem = name.indexOf('[')) > 0) - name = name.substring(0, tem); - if ((tem = name.indexOf('(')) > 0) - name = name.substring(0, tem); - if (name.endsWith("H")) - name = name.substring(0, name.length()-1); - } - Band nb; - switch (e.kind) { - case Attribute.EK_INT: - nb = newElemBand(e, name, ab); - break; - case Attribute.EK_BCI: - if (!e.flagTest(Attribute.EF_DELTA)) { - // PH: transmit R(bci), store bci - nb = ab.newIntBand(name, BCI5); - } else { - // POH: transmit D(R(bci)), store bci - nb = ab.newIntBand(name, BRANCH5); - } - // Note: No case for BYTE1 here. - break; - case Attribute.EK_BCO: - // OH: transmit D(R(bci)), store D(bci) - nb = ab.newIntBand(name, BRANCH5); - // Note: No case for BYTE1 here. - break; - case Attribute.EK_FLAG: - assert(!e.flagTest(Attribute.EF_SIGN)); - nb = newElemBand(e, name, ab); - break; - case Attribute.EK_REPL: - assert(!e.flagTest(Attribute.EF_SIGN)); - nb = newElemBand(e, name, ab); - makeNewAttributeBands(pfx, e.body, ab); - break; - case Attribute.EK_UN: - nb = newElemBand(e, name, ab); - makeNewAttributeBands(pfx, e.body, ab); - break; - case Attribute.EK_CASE: - if (!e.flagTest(Attribute.EF_BACK)) { - // If it's not a duplicate body, make the bands. - makeNewAttributeBands(pfx, e.body, ab); - } - continue; // no new band to make - case Attribute.EK_REF: - byte refKind = e.refKind; - boolean nullOK = e.flagTest(Attribute.EF_NULL); - nb = ab.newCPRefBand(name, UNSIGNED5, refKind, nullOK); - // Note: No case for BYTE1 here. - break; - case Attribute.EK_CALL: - continue; // no new band to make - case Attribute.EK_CBLE: - makeNewAttributeBands(pfx, e.body, ab); - continue; // no new band to make - default: assert(false); continue; - } - if (verbose > 1) { - Utils.log.fine("New attribute band "+nb); - } - } + MultiBand ab) { + for (int i = 0; i < elems.length; i++) { + Attribute.Layout.Element e = elems[i]; + String name = pfx+ab.size()+"_"+e.layout; + { + int tem; + if ((tem = name.indexOf('[')) > 0) + name = name.substring(0, tem); + if ((tem = name.indexOf('(')) > 0) + name = name.substring(0, tem); + if (name.endsWith("H")) + name = name.substring(0, name.length()-1); + } + Band nb; + switch (e.kind) { + case Attribute.EK_INT: + nb = newElemBand(e, name, ab); + break; + case Attribute.EK_BCI: + if (!e.flagTest(Attribute.EF_DELTA)) { + // PH: transmit R(bci), store bci + nb = ab.newIntBand(name, BCI5); + } else { + // POH: transmit D(R(bci)), store bci + nb = ab.newIntBand(name, BRANCH5); + } + // Note: No case for BYTE1 here. + break; + case Attribute.EK_BCO: + // OH: transmit D(R(bci)), store D(bci) + nb = ab.newIntBand(name, BRANCH5); + // Note: No case for BYTE1 here. + break; + case Attribute.EK_FLAG: + assert(!e.flagTest(Attribute.EF_SIGN)); + nb = newElemBand(e, name, ab); + break; + case Attribute.EK_REPL: + assert(!e.flagTest(Attribute.EF_SIGN)); + nb = newElemBand(e, name, ab); + makeNewAttributeBands(pfx, e.body, ab); + break; + case Attribute.EK_UN: + nb = newElemBand(e, name, ab); + makeNewAttributeBands(pfx, e.body, ab); + break; + case Attribute.EK_CASE: + if (!e.flagTest(Attribute.EF_BACK)) { + // If it's not a duplicate body, make the bands. + makeNewAttributeBands(pfx, e.body, ab); + } + continue; // no new band to make + case Attribute.EK_REF: + byte refKind = e.refKind; + boolean nullOK = e.flagTest(Attribute.EF_NULL); + nb = ab.newCPRefBand(name, UNSIGNED5, refKind, nullOK); + // Note: No case for BYTE1 here. + break; + case Attribute.EK_CALL: + continue; // no new band to make + case Attribute.EK_CBLE: + makeNewAttributeBands(pfx, e.body, ab); + continue; // no new band to make + default: assert(false); continue; + } + if (verbose > 1) { + Utils.log.fine("New attribute band "+nb); + } + } } private Band newElemBand(Attribute.Layout.Element e, String name, MultiBand ab) { - if (e.flagTest(Attribute.EF_SIGN)) { - return ab.newIntBand(name, SIGNED5); - } else if (e.len == 1) { - return ab.newIntBand(name, BYTE1); // Not ByteBand, please. - } else { - return ab.newIntBand(name, UNSIGNED5); - } + if (e.flagTest(Attribute.EF_SIGN)) { + return ab.newIntBand(name, SIGNED5); + } else if (e.len == 1) { + return ab.newIntBand(name, BYTE1); // Not ByteBand, please. + } else { + return ab.newIntBand(name, UNSIGNED5); + } } protected int setAttributeLayoutIndex(Attribute.Layout def, int index) { - int ctype = def.ctype; - assert(ATTR_INDEX_OVERFLOW <= index && index < attrIndexLimit[ctype]); - List defList = attrDefs[ctype]; - if (index == ATTR_INDEX_OVERFLOW) { - // Overflow attribute. - index = defList.size(); - defList.add(def); - if (verbose > 0) - Utils.log.info("Adding new attribute at "+def +": "+index); - attrIndexTable.put(def, new Integer(index)); - return index; - } + int ctype = def.ctype; + assert(ATTR_INDEX_OVERFLOW <= index && index < attrIndexLimit[ctype]); + List defList = attrDefs[ctype]; + if (index == ATTR_INDEX_OVERFLOW) { + // Overflow attribute. + index = defList.size(); + defList.add(def); + if (verbose > 0) + Utils.log.info("Adding new attribute at "+def +": "+index); + attrIndexTable.put(def, new Integer(index)); + return index; + } - // Detect redefinitions: - if (testBit(attrDefSeen[ctype], 1L< (attrClassFileVersionMask == 0? 2:0)) - Utils.log.fine("Fixing new attribute at "+index - +": "+def - +(defList.get(index) == null? "": - "; replacing "+defList.get(index))); - attrFlagMask[ctype] |= (1L< (attrClassFileVersionMask == 0? 2:0)) + Utils.log.fine("Fixing new attribute at "+index + +": "+def + +(defList.get(index) == null? "": + "; replacing "+defList.get(index))); + attrFlagMask[ctype] |= (1L<= shortCodeLimits.length) return LONG_CODE_HEADER; - int siglen = code.getMethod().getArgumentSize(); - assert(l0 >= siglen); // enough locals for signature! - if (l0 < siglen) return LONG_CODE_HEADER; - int l1 = l0 - siglen; // do not count locals required by the signature - int lims = shortCodeLimits[h][0]; - int liml = shortCodeLimits[h][1]; - if (s >= lims || l1 >= liml) return LONG_CODE_HEADER; - int sc = shortCodeHeader_h_base(h); - sc += s + lims*l1; - if (sc > 255) return LONG_CODE_HEADER; - assert(shortCodeHeader_max_stack(sc) == s); - assert(shortCodeHeader_max_na_locals(sc) == l1); - assert(shortCodeHeader_handler_count(sc) == h); - return sc; + int s = code.max_stack; + int l0 = code.max_locals; + int h = code.handler_class.length; + if (h >= shortCodeLimits.length) return LONG_CODE_HEADER; + int siglen = code.getMethod().getArgumentSize(); + assert(l0 >= siglen); // enough locals for signature! + if (l0 < siglen) return LONG_CODE_HEADER; + int l1 = l0 - siglen; // do not count locals required by the signature + int lims = shortCodeLimits[h][0]; + int liml = shortCodeLimits[h][1]; + if (s >= lims || l1 >= liml) return LONG_CODE_HEADER; + int sc = shortCodeHeader_h_base(h); + sc += s + lims*l1; + if (sc > 255) return LONG_CODE_HEADER; + assert(shortCodeHeader_max_stack(sc) == s); + assert(shortCodeHeader_max_na_locals(sc) == l1); + assert(shortCodeHeader_handler_count(sc) == h); + return sc; } static final int LONG_CODE_HEADER = 0; static int shortCodeHeader_handler_count(int sc) { - assert(sc > 0 && sc <= 255); - for (int h = 0; ; h++) { - if (sc < shortCodeHeader_h_base(h+1)) - return h; - } + assert(sc > 0 && sc <= 255); + for (int h = 0; ; h++) { + if (sc < shortCodeHeader_h_base(h+1)) + return h; + } } static int shortCodeHeader_max_stack(int sc) { - int h = shortCodeHeader_handler_count(sc); - int lims = shortCodeLimits[h][0]; - return (sc - shortCodeHeader_h_base(h)) % lims; + int h = shortCodeHeader_handler_count(sc); + int lims = shortCodeLimits[h][0]; + return (sc - shortCodeHeader_h_base(h)) % lims; } static int shortCodeHeader_max_na_locals(int sc) { - int h = shortCodeHeader_handler_count(sc); - int lims = shortCodeLimits[h][0]; - return (sc - shortCodeHeader_h_base(h)) / lims; + int h = shortCodeHeader_handler_count(sc); + int lims = shortCodeLimits[h][0]; + return (sc - shortCodeHeader_h_base(h)) / lims; } private static int shortCodeHeader_h_base(int h) { - assert(h <= shortCodeLimits.length); - int sc = 1; - for (int h0 = 0; h0 < h; h0++) { - int lims = shortCodeLimits[h0][0]; - int liml = shortCodeLimits[h0][1]; - sc += lims * liml; - } - return sc; + assert(h <= shortCodeLimits.length); + int sc = 1; + for (int h0 = 0; h0 < h; h0++) { + int lims = shortCodeLimits[h0][0]; + int liml = shortCodeLimits[h0][1]; + sc += lims * liml; + } + return sc; } // utilities for accessing the bc_label band: protected void putLabel(IntBand bc_label, Code c, int pc, int targetPC) { - bc_label.putInt(c.encodeBCI(targetPC) - c.encodeBCI(pc)); + bc_label.putInt(c.encodeBCI(targetPC) - c.encodeBCI(pc)); } protected int getLabel(IntBand bc_label, Code c, int pc) { - return c.decodeBCI(bc_label.getInt() + c.encodeBCI(pc)); + return c.decodeBCI(bc_label.getInt() + c.encodeBCI(pc)); } protected CPRefBand getCPRefOpBand(int bc) { - switch (Instruction.getCPRefOpTag(bc)) { - case CONSTANT_Class: - return bc_classref; - case CONSTANT_Fieldref: - return bc_fieldref; - case CONSTANT_Methodref: - return bc_methodref; - case CONSTANT_InterfaceMethodref: - return bc_imethodref; - case CONSTANT_Literal: - switch (bc) { - case _ildc: case _ildc_w: - return bc_intref; - case _fldc: case _fldc_w: - return bc_floatref; - case _lldc2_w: - return bc_longref; - case _dldc2_w: - return bc_doubleref; - case _aldc: case _aldc_w: - return bc_stringref; - case _cldc: case _cldc_w: - return bc_classref; - } - break; - } - assert(false); - return null; + switch (Instruction.getCPRefOpTag(bc)) { + case CONSTANT_Class: + return bc_classref; + case CONSTANT_Fieldref: + return bc_fieldref; + case CONSTANT_Methodref: + return bc_methodref; + case CONSTANT_InterfaceMethodref: + return bc_imethodref; + case CONSTANT_Literal: + switch (bc) { + case _ildc: case _ildc_w: + return bc_intref; + case _fldc: case _fldc_w: + return bc_floatref; + case _lldc2_w: + return bc_longref; + case _dldc2_w: + return bc_doubleref; + case _aldc: case _aldc_w: + return bc_stringref; + case _cldc: case _cldc_w: + return bc_classref; + } + break; + } + assert(false); + return null; } protected CPRefBand selfOpRefBand(int self_bc) { - assert(Instruction.isSelfLinkerOp(self_bc)); - int idx = (self_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); - if (!isSuper) - return isField? bc_thisfield: bc_thismethod; - else - return isField? bc_superfield: bc_supermethod; + assert(Instruction.isSelfLinkerOp(self_bc)); + int idx = (self_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); + if (!isSuper) + return isField? bc_thisfield: bc_thismethod; + else + return isField? bc_superfield: bc_supermethod; } //////////////////////////////////////////////////////////////////// @@ -2347,317 +2347,319 @@ class BandStructure implements Constants static int nextSeqForDebug; static File dumpDir; static OutputStream getDumpStream(Band b, String ext) throws IOException { - return getDumpStream(b.name, b.seqForDebug, ext, b); + return getDumpStream(b.name, b.seqForDebug, ext, b); } static OutputStream getDumpStream(Index ix, String ext) throws IOException { - if (ix.size() == 0) return new ByteArrayOutputStream(); - int seq = ConstantPool.TAG_ORDER[ix.cpMap[0].tag]; - return getDumpStream(ix.debugName, seq, ext, ix); + if (ix.size() == 0) return new ByteArrayOutputStream(); + int seq = ConstantPool.TAG_ORDER[ix.cpMap[0].tag]; + return getDumpStream(ix.debugName, seq, ext, ix); } static OutputStream getDumpStream(String name, int seq, String ext, Object b) throws IOException { - if (dumpDir == null) { - dumpDir = File.createTempFile("BD_", "", new File(".")); - dumpDir.delete(); - if (dumpDir.mkdir()) - Utils.log.info("Dumping bands to "+dumpDir); - } - name = name.replace('(', ' ').replace(')', ' '); - name = name.replace('/', ' '); - name = name.replace('*', ' '); - name = name.trim().replace(' ','_'); - name = ((10000+seq) + "_" + name).substring(1); - File dumpFile = new File(dumpDir, name+ext); - Utils.log.info("Dumping "+b+" to "+dumpFile); - return new BufferedOutputStream(new FileOutputStream(dumpFile)); + if (dumpDir == null) { + dumpDir = File.createTempFile("BD_", "", new File(".")); + dumpDir.delete(); + if (dumpDir.mkdir()) + Utils.log.info("Dumping bands to "+dumpDir); + } + name = name.replace('(', ' ').replace(')', ' '); + name = name.replace('/', ' '); + name = name.replace('*', ' '); + name = name.trim().replace(' ','_'); + name = ((10000+seq) + "_" + name).substring(1); + File dumpFile = new File(dumpDir, name+ext); + Utils.log.info("Dumping "+b+" to "+dumpFile); + return new BufferedOutputStream(new FileOutputStream(dumpFile)); } // DEBUG ONLY: Validate me at each length change. static boolean assertCanChangeLength(Band b) { - switch (b.phase) { - case COLLECT_PHASE: - case READ_PHASE: - return true; - } - return false; + switch (b.phase) { + case COLLECT_PHASE: + case READ_PHASE: + return true; + } + return false; } // DEBUG ONLY: Validate a phase. static boolean assertPhase(Band b, int phaseExpected) { - if (b.phase() != phaseExpected) { - Utils.log.warning("phase expected "+phaseExpected+" was "+b.phase()+" in "+b); - return false; - } - return true; + if (b.phase() != phaseExpected) { + Utils.log.warning("phase expected "+phaseExpected+" was "+b.phase()+" in "+b); + return false; + } + return true; } // DEBUG ONLY: Tells whether verbosity is turned on. static int verbose() { - return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE); + return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE); } // DEBUG ONLY: Validate me at each phase change. static boolean assertPhaseChangeOK(Band b, int p0, int p1) { - switch (p0*10+p1) { - /// Writing phases: - case NO_PHASE*10+COLLECT_PHASE: - // Ready to collect data from the input classes. - assert(!b.isReader()); - assert(b.capacity() >= 0); - assert(b.length() == 0); - return true; - case COLLECT_PHASE*10+FROZEN_PHASE: - case FROZEN_PHASE*10+FROZEN_PHASE: - assert(b.length() == 0); - return true; - case COLLECT_PHASE*10+WRITE_PHASE: - case FROZEN_PHASE*10+WRITE_PHASE: - // Data is all collected. Ready to write bytes to disk. - return true; - case WRITE_PHASE*10+DONE_PHASE: - // Done writing to disk. Ready to reset, in principle. - return true; + switch (p0*10+p1) { + /// Writing phases: + case NO_PHASE*10+COLLECT_PHASE: + // Ready to collect data from the input classes. + assert(!b.isReader()); + assert(b.capacity() >= 0); + assert(b.length() == 0); + return true; + case COLLECT_PHASE*10+FROZEN_PHASE: + case FROZEN_PHASE*10+FROZEN_PHASE: + assert(b.length() == 0); + return true; + case COLLECT_PHASE*10+WRITE_PHASE: + case FROZEN_PHASE*10+WRITE_PHASE: + // Data is all collected. Ready to write bytes to disk. + return true; + case WRITE_PHASE*10+DONE_PHASE: + // Done writing to disk. Ready to reset, in principle. + return true; - /// Reading phases: - case NO_PHASE*10+EXPECT_PHASE: - assert(b.isReader()); - assert(b.capacity() < 0); - return true; - case EXPECT_PHASE*10+READ_PHASE: - // Ready to read values from disk. - assert(Math.max(0,b.capacity()) >= b.valuesExpected()); - assert(b.length() <= 0); - return true; - case READ_PHASE*10+DISBURSE_PHASE: - // Ready to disburse values. - assert(b.valuesRemainingForDebug() == b.length()); - return true; - case DISBURSE_PHASE*10+DONE_PHASE: - // Done disbursing values. Ready to reset, in principle. - assert(assertDoneDisbursing(b)); - return true; - } - if (p0 == p1) - Utils.log.warning("Already in phase "+p0); - else - Utils.log.warning("Unexpected phase "+p0+" -> "+p1); - return false; + /// Reading phases: + case NO_PHASE*10+EXPECT_PHASE: + assert(b.isReader()); + assert(b.capacity() < 0); + return true; + case EXPECT_PHASE*10+READ_PHASE: + // Ready to read values from disk. + assert(Math.max(0,b.capacity()) >= b.valuesExpected()); + assert(b.length() <= 0); + return true; + case READ_PHASE*10+DISBURSE_PHASE: + // Ready to disburse values. + assert(b.valuesRemainingForDebug() == b.length()); + return true; + case DISBURSE_PHASE*10+DONE_PHASE: + // Done disbursing values. Ready to reset, in principle. + assert(assertDoneDisbursing(b)); + return true; + } + if (p0 == p1) + Utils.log.warning("Already in phase "+p0); + else + Utils.log.warning("Unexpected phase "+p0+" -> "+p1); + return false; } static private boolean assertDoneDisbursing(Band b) { - if (b.phase != DISBURSE_PHASE) { - Utils.log.warning("assertDoneDisbursing: still in phase "+b.phase+": "+b); - if (verbose() <= 1) return false; // fail now - } - int left = b.valuesRemainingForDebug(); - if (left > 0) { - Utils.log.warning("assertDoneDisbursing: "+left+" values left in "+b); - if (verbose() <= 1) return false; // fail now - } - if (b instanceof MultiBand) { - MultiBand mb = (MultiBand) b; - for (int i = 0; i < mb.bandCount; i++) { - Band sub = mb.bands[i]; - if (sub.phase != DONE_PHASE) { - Utils.log.warning("assertDoneDisbursing: sub-band still in phase "+sub.phase+": "+sub); - if (verbose() <= 1) return false; // fail now - } - } - } - return true; + if (b.phase != DISBURSE_PHASE) { + Utils.log.warning("assertDoneDisbursing: still in phase "+b.phase+": "+b); + if (verbose() <= 1) return false; // fail now + } + int left = b.valuesRemainingForDebug(); + if (left > 0) { + Utils.log.warning("assertDoneDisbursing: "+left+" values left in "+b); + if (verbose() <= 1) return false; // fail now + } + if (b instanceof MultiBand) { + MultiBand mb = (MultiBand) b; + for (int i = 0; i < mb.bandCount; i++) { + Band sub = mb.bands[i]; + if (sub.phase != DONE_PHASE) { + Utils.log.warning("assertDoneDisbursing: sub-band still in phase "+sub.phase+": "+sub); + if (verbose() <= 1) return false; // fail now + } + } + } + return true; } static private void printCDecl(Band b) { - if (b instanceof MultiBand) { - MultiBand mb = (MultiBand) b; - for (int i = 0; i < mb.bandCount; i++) { - printCDecl(mb.bands[i]); - } - return; - } - String ixS = "NULL"; - if (b instanceof CPRefBand) { - Index ix = ((CPRefBand)b).index; - if (ix != null) ixS = "INDEX("+ix.debugName+")"; - } - Coding[] knownc = { BYTE1, CHAR3, BCI5, BRANCH5, UNSIGNED5, - UDELTA5, SIGNED5, DELTA5, MDELTA5 }; - String[] knowns = { "BYTE1", "CHAR3", "BCI5", "BRANCH5", "UNSIGNED5", - "UDELTA5", "SIGNED5", "DELTA5", "MDELTA5" }; - Coding rc = b.regularCoding; - int rci = Arrays.asList(knownc).indexOf(rc); - String cstr; - if (rci >= 0) - cstr = knowns[rci]; - else - cstr = "CODING"+rc.keyString(); - System.out.println(" BAND_INIT(\""+b.name()+"\"" - +", "+cstr+", "+ixS+"),"); + if (b instanceof MultiBand) { + MultiBand mb = (MultiBand) b; + for (int i = 0; i < mb.bandCount; i++) { + printCDecl(mb.bands[i]); + } + return; + } + String ixS = "NULL"; + if (b instanceof CPRefBand) { + Index ix = ((CPRefBand)b).index; + if (ix != null) ixS = "INDEX("+ix.debugName+")"; + } + Coding[] knownc = { BYTE1, CHAR3, BCI5, BRANCH5, UNSIGNED5, + UDELTA5, SIGNED5, DELTA5, MDELTA5 }; + String[] knowns = { "BYTE1", "CHAR3", "BCI5", "BRANCH5", "UNSIGNED5", + "UDELTA5", "SIGNED5", "DELTA5", "MDELTA5" }; + Coding rc = b.regularCoding; + int rci = Arrays.asList(knownc).indexOf(rc); + String cstr; + if (rci >= 0) + cstr = knowns[rci]; + else + cstr = "CODING"+rc.keyString(); + System.out.println(" BAND_INIT(\""+b.name()+"\"" + +", "+cstr+", "+ixS+"),"); } private HashMap prevForAssertMap; // DEBUG ONLY: Record something about the band order. boolean notePrevForAssert(Band b, Band p) { - if (prevForAssertMap == null) - prevForAssertMap = new HashMap(); - prevForAssertMap.put(b, p); - return true; + if (prevForAssertMap == null) + prevForAssertMap = new HashMap(); + prevForAssertMap.put(b, p); + return true; } // DEBUG ONLY: Validate next input band. private boolean assertReadyToReadFrom(Band b, InputStream in) throws IOException { - Band p = (Band) prevForAssertMap.get(b); - // Any previous band must be done reading before this one starts. - if (p != null && phaseCmp(p.phase(), DISBURSE_PHASE) < 0) { - Utils.log.warning("Previous band not done reading."); - Utils.log.info(" Previous band: "+p); - Utils.log.info(" Next band: "+b); - Thread.dumpStack(); - assert(verbose > 0); // die unless verbose is true - } - String name = b.name; - if (optDebugBands && !name.startsWith("(")) { - // Verify synchronization between reader & writer: - StringBuffer buf = new StringBuffer(); - int ch; - while ((ch = in.read()) > 0) - buf.append((char)ch); - String inName = buf.toString(); - if (!inName.equals(name)) { - StringBuffer sb = new StringBuffer(); - sb.append("Expected "+name+" but read: "); - inName += (char)ch; - while (inName.length() < 10) - inName += (char)in.read(); - for (int i = 0; i < inName.length(); i++) - sb.append(inName.charAt(i)); - Utils.log.warning(sb.toString()); - return false; - } - } - return true; + Band p = (Band) prevForAssertMap.get(b); + // Any previous band must be done reading before this one starts. + if (p != null && phaseCmp(p.phase(), DISBURSE_PHASE) < 0) { + Utils.log.warning("Previous band not done reading."); + Utils.log.info(" Previous band: "+p); + Utils.log.info(" Next band: "+b); + Thread.dumpStack(); + assert(verbose > 0); // die unless verbose is true + } + String name = b.name; + if (optDebugBands && !name.startsWith("(")) { + // Verify synchronization between reader & writer: + StringBuffer buf = new StringBuffer(); + int ch; + while ((ch = in.read()) > 0) + buf.append((char)ch); + String inName = buf.toString(); + if (!inName.equals(name)) { + StringBuffer sb = new StringBuffer(); + sb.append("Expected "+name+" but read: "); + inName += (char)ch; + while (inName.length() < 10) + inName += (char)in.read(); + for (int i = 0; i < inName.length(); i++) + sb.append(inName.charAt(i)); + Utils.log.warning(sb.toString()); + return false; + } + } + return true; } // DEBUG ONLY: Make sure a bunch of cprefs are correct. private boolean assertValidCPRefs(CPRefBand b) { - if (b.index == null) return true; - int limit = b.index.size()+1; - for (int i = 0; i < b.length(); i++) { - int v = b.valueAtForDebug(i); - if (v < 0 || v >= limit) { - Utils.log.warning("CP ref out of range "+ - "["+i+"] = "+v+" in "+b); - return false; - } - } - return true; + if (b.index == null) return true; + int limit = b.index.size()+1; + for (int i = 0; i < b.length(); i++) { + int v = b.valueAtForDebug(i); + if (v < 0 || v >= limit) { + Utils.log.warning("CP ref out of range "+ + "["+i+"] = "+v+" in "+b); + return false; + } + } + return true; } // DEBUG ONLY: Maybe write a debugging cookie to next output band. private boolean assertReadyToWriteTo(Band b, OutputStream out) throws IOException { - Band p = (Band) prevForAssertMap.get(b); - // Any previous band must be done writing before this one starts. - if (p != null && phaseCmp(p.phase(), DONE_PHASE) < 0) { - Utils.log.warning("Previous band not done writing."); - Utils.log.info(" Previous band: "+p); - Utils.log.info(" Next band: "+b); - Thread.dumpStack(); - assert(verbose > 0); // die unless verbose is true - } - String name = b.name; - if (optDebugBands && !name.startsWith("(")) { - // Verify synchronization between reader & writer: - for (int j = 0; j < name.length(); j++) { - out.write((byte)name.charAt(j)); - } - out.write((byte)0); - } - return true; + Band p = (Band) prevForAssertMap.get(b); + // Any previous band must be done writing before this one starts. + if (p != null && phaseCmp(p.phase(), DONE_PHASE) < 0) { + Utils.log.warning("Previous band not done writing."); + Utils.log.info(" Previous band: "+p); + Utils.log.info(" Next band: "+b); + Thread.dumpStack(); + assert(verbose > 0); // die unless verbose is true + } + String name = b.name; + if (optDebugBands && !name.startsWith("(")) { + // Verify synchronization between reader & writer: + for (int j = 0; j < name.length(); j++) { + out.write((byte)name.charAt(j)); + } + out.write((byte)0); + } + return true; } protected static boolean testBit(int flags, int bitMask) { - return (flags & bitMask) != 0; + return (flags & bitMask) != 0; } protected static int setBit(int flags, int bitMask, boolean z) { - return z ? (flags | bitMask) : (flags &~ bitMask); + return z ? (flags | bitMask) : (flags &~ bitMask); } protected static boolean testBit(long flags, long bitMask) { - return (flags & bitMask) != 0; + return (flags & bitMask) != 0; } protected static long setBit(long flags, long bitMask, boolean z) { - return z ? (flags | bitMask) : (flags &~ bitMask); + return z ? (flags | bitMask) : (flags &~ bitMask); } static void printArrayTo(PrintStream ps, int[] values, int start, int end) { - int len = end-start; - for (int i = 0; i < len; i++) { - if (i % 10 == 0) - ps.println(); - else - ps.print(" "); - ps.print(values[start+i]); - } - ps.println(); + int len = end-start; + for (int i = 0; i < len; i++) { + if (i % 10 == 0) + ps.println(); + else + ps.print(" "); + ps.print(values[start+i]); + } + ps.println(); } static void printArrayTo(PrintStream ps, Entry[] cpMap, int start, int end) { - StringBuffer buf = new StringBuffer(); - int len = end-start; - for (int i = 0; i < len; i++) { - String s = cpMap[start+i].stringValue(); - buf.setLength(0); - for (int j = 0; j < s.length(); j++) { - char ch = s.charAt(j); - if (!(ch < ' ' || ch > '~' || ch == '\\')) { - buf.append(ch); - } else if (ch == '\n') { - buf.append("\\n"); - } else if (ch == '\t') { - buf.append("\\t"); - } else if (ch == '\r') { - buf.append("\\r"); - } else { - buf.append("\\x"+Integer.toHexString(ch)); - } - } - ps.println(buf); - } + StringBuffer buf = new StringBuffer(); + int len = end-start; + for (int i = 0; i < len; i++) { + String s = cpMap[start+i].stringValue(); + buf.setLength(0); + for (int j = 0; j < s.length(); j++) { + char ch = s.charAt(j); + if (!(ch < ' ' || ch > '~' || ch == '\\')) { + buf.append(ch); + } else if (ch == '\n') { + buf.append("\\n"); + } else if (ch == '\t') { + buf.append("\\t"); + } else if (ch == '\r') { + buf.append("\\r"); + } else { + buf.append("\\x"+Integer.toHexString(ch)); + } + } + ps.println(buf); + } } // Utilities for reallocating: protected static Object[] realloc(Object[] a, int len) { - java.lang.Class elt = a.getClass().getComponentType(); - Object[] na = (Object[]) java.lang.reflect.Array.newInstance(elt, len); - System.arraycopy(a, 0, na, 0, Math.min(a.length, len)); - return na; + java.lang.Class elt = a.getClass().getComponentType(); + Object[] na = (Object[]) java.lang.reflect.Array.newInstance(elt, len); + System.arraycopy(a, 0, na, 0, Math.min(a.length, len)); + return na; } protected static Object[] realloc(Object[] a) { - return realloc(a, Math.max(10, a.length*2)); + return realloc(a, Math.max(10, a.length*2)); } static private int[] noInts = {}; protected static int[] realloc(int[] a, int len) { - if (len == 0) return noInts; - if (a == null) return new int[len]; - int[] na = new int[len]; - System.arraycopy(a, 0, na, 0, Math.min(a.length, len)); - return na; + if (len == 0) return noInts; + if (a == null) return new int[len]; + int[] na = new int[len]; + System.arraycopy(a, 0, na, 0, Math.min(a.length, len)); + return na; } protected static int[] realloc(int[] a) { - return realloc(a, Math.max(10, a.length*2)); + return realloc(a, Math.max(10, a.length*2)); } static private byte[] noBytes = {}; protected static byte[] realloc(byte[] a, int len) { - if (len == 0) return noBytes; - if (a == null) return new byte[len]; - byte[] na = new byte[len]; - System.arraycopy(a, 0, na, 0, Math.min(a.length, len)); - return na; + if (len == 0) return noBytes; + if (a == null) return new byte[len]; + byte[] na = new byte[len]; + System.arraycopy(a, 0, na, 0, Math.min(a.length, len)); + return na; } protected static byte[] realloc(byte[] a) { - return realloc(a, Math.max(10, a.length*2)); + return realloc(a, Math.max(10, a.length*2)); } } + + diff --git a/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java b/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java --- jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java +++ jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - + package com.sun.java.util.jar.pack; import java.io.*; @@ -37,7 +37,7 @@ class ConstantPool implements Constants private ConstantPool() {} // do not instantiate static int verbose() { - return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE); + return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE); } // Uniquification tables for factory methods: @@ -53,659 +53,659 @@ class ConstantPool implements Constants * Also used to back up more complex constant pool entries, like Class. */ public static synchronized Utf8Entry getUtf8Entry(String value) { - Utf8Entry e = (Utf8Entry) utf8Entries.get(value); - if (e == null) { - e = new Utf8Entry(value); - utf8Entries.put(e.stringValue(), e); - } - return e; + Utf8Entry e = (Utf8Entry) utf8Entries.get(value); + if (e == null) { + e = new Utf8Entry(value); + utf8Entries.put(e.stringValue(), e); + } + return e; } /** Factory for Class constants. */ public static synchronized ClassEntry getClassEntry(String name) { - ClassEntry e = (ClassEntry) classEntries.get(name); - if (e == null) { - e = (ClassEntry) new ClassEntry(getUtf8Entry(name)); - assert(name.equals(e.stringValue())); - classEntries.put(e.stringValue(), e); - } - return e; + ClassEntry e = (ClassEntry) classEntries.get(name); + if (e == null) { + e = (ClassEntry) new ClassEntry(getUtf8Entry(name)); + assert(name.equals(e.stringValue())); + classEntries.put(e.stringValue(), e); + } + return e; } /** Factory for literal constants (String, Integer, etc.). */ public static synchronized LiteralEntry getLiteralEntry(Comparable value) { - LiteralEntry e = (LiteralEntry) literalEntries.get(value); - if (e == null) { - if (value instanceof String) - e = new StringEntry(getUtf8Entry((String)value)); - else - e = new NumberEntry((Number)value); - literalEntries.put(value, e); - } - return e; + LiteralEntry e = (LiteralEntry) literalEntries.get(value); + if (e == null) { + if (value instanceof String) + e = new StringEntry(getUtf8Entry((String)value)); + else + e = new NumberEntry((Number)value); + literalEntries.put(value, e); + } + return e; } /** Factory for literal constants (String, Integer, etc.). */ public static synchronized StringEntry getStringEntry(String value) { - return (StringEntry) getLiteralEntry(value); + return (StringEntry) getLiteralEntry(value); } /** Factory for signature (type) constants. */ public static synchronized SignatureEntry getSignatureEntry(String type) { - SignatureEntry e = (SignatureEntry) signatureEntries.get(type); - if (e == null) { - e = new SignatureEntry(type); - assert(e.stringValue().equals(type)); - signatureEntries.put(type, e); - } - return e; + SignatureEntry e = (SignatureEntry) signatureEntries.get(type); + if (e == null) { + e = new SignatureEntry(type); + assert(e.stringValue().equals(type)); + signatureEntries.put(type, e); + } + return e; } // Convenience overloading. public static SignatureEntry getSignatureEntry(Utf8Entry formRef, ClassEntry[] classRefs) { - return getSignatureEntry(SignatureEntry.stringValueOf(formRef, classRefs)); + return getSignatureEntry(SignatureEntry.stringValueOf(formRef, classRefs)); } /** Factory for descriptor (name-and-type) constants. */ public static synchronized DescriptorEntry getDescriptorEntry(Utf8Entry nameRef, SignatureEntry typeRef) { - String key = DescriptorEntry.stringValueOf(nameRef, typeRef); - DescriptorEntry e = (DescriptorEntry) descriptorEntries.get(key); - if (e == null) { - e = new DescriptorEntry(nameRef, typeRef); - assert(e.stringValue().equals(key)) - : (e.stringValue()+" != "+(key)); - descriptorEntries.put(key, e); - } - return e; + String key = DescriptorEntry.stringValueOf(nameRef, typeRef); + DescriptorEntry e = (DescriptorEntry) descriptorEntries.get(key); + if (e == null) { + e = new DescriptorEntry(nameRef, typeRef); + assert(e.stringValue().equals(key)) + : (e.stringValue()+" != "+(key)); + descriptorEntries.put(key, e); + } + return e; } // Convenience overloading. public static DescriptorEntry getDescriptorEntry(Utf8Entry nameRef, Utf8Entry typeRef) { - return getDescriptorEntry(nameRef, getSignatureEntry(typeRef.stringValue())); + return getDescriptorEntry(nameRef, getSignatureEntry(typeRef.stringValue())); } /** Factory for member reference constants. */ public static synchronized MemberEntry getMemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) { - String key = MemberEntry.stringValueOf(tag, classRef, descRef); - MemberEntry e = (MemberEntry) memberEntries.get(key); - if (e == null) { - e = new MemberEntry(tag, classRef, descRef); - assert(e.stringValue().equals(key)) - : (e.stringValue()+" != "+(key)); - memberEntries.put(key, e); - } - return e; + String key = MemberEntry.stringValueOf(tag, classRef, descRef); + MemberEntry e = (MemberEntry) memberEntries.get(key); + if (e == null) { + e = new MemberEntry(tag, classRef, descRef); + assert(e.stringValue().equals(key)) + : (e.stringValue()+" != "+(key)); + memberEntries.put(key, e); + } + return e; } /** Entries in the constant pool. */ public static abstract class Entry implements Comparable { - protected final byte tag; // a CONSTANT_foo code - protected int valueHash; // cached hashCode + protected final byte tag; // a CONSTANT_foo code + protected int valueHash; // cached hashCode - protected Entry(byte tag) { - this.tag = tag; - } + protected Entry(byte tag) { + this.tag = tag; + } - public final byte getTag() { - return tag; - } + public final byte getTag() { + return tag; + } - public Entry getRef(int i) { - return null; - } + public Entry getRef(int i) { + return null; + } - public boolean sameTagAs(Object o) { - return (o instanceof Entry) && ((Entry)o).tag == tag; - } - public boolean eq(Entry that) { // same reference - assert(that != null); - return this == that || this.equals(that); - } + public boolean sameTagAs(Object o) { + return (o instanceof Entry) && ((Entry)o).tag == tag; + } + public boolean eq(Entry that) { // same reference + assert(that != null); + return this == that || this.equals(that); + } - // Equality of Entries is value-based. - public abstract boolean equals(Object o); - public final int hashCode() { - if (valueHash == 0) { - valueHash = computeValueHash(); - if (valueHash == 0) valueHash = 1; - } - return valueHash; - } - protected abstract int computeValueHash(); + // Equality of Entries is value-based. + public abstract boolean equals(Object o); + public final int hashCode() { + if (valueHash == 0) { + valueHash = computeValueHash(); + if (valueHash == 0) valueHash = 1; + } + return valueHash; + } + protected abstract int computeValueHash(); - public abstract int compareTo(Object o); + public abstract int compareTo(Object o); - protected int superCompareTo(Object o) { - Entry that = (Entry) o; + protected int superCompareTo(Object o) { + Entry that = (Entry) o; - if (this.tag != that.tag) { - return TAG_ORDER[this.tag] - TAG_ORDER[that.tag]; - } + if (this.tag != that.tag) { + return TAG_ORDER[this.tag] - TAG_ORDER[that.tag]; + } - return 0; // subclasses must refine this - } + return 0; // subclasses must refine this + } - public final boolean isDoubleWord() { - return tag == CONSTANT_Double || tag == CONSTANT_Long; - } + public final boolean isDoubleWord() { + return tag == CONSTANT_Double || tag == CONSTANT_Long; + } - public final boolean tagMatches(int tag) { - return (this.tag == tag); - } + public final boolean tagMatches(int tag) { + return (this.tag == tag); + } - public String toString() { - String valuePrint = stringValue(); - if (verbose() > 4) { - if (valueHash != 0) - valuePrint += " hash="+valueHash; - valuePrint += " id="+System.identityHashCode(this); - } - return tagName(tag)+"="+valuePrint; - } - public abstract String stringValue(); + public String toString() { + String valuePrint = stringValue(); + if (verbose() > 4) { + if (valueHash != 0) + valuePrint += " hash="+valueHash; + valuePrint += " id="+System.identityHashCode(this); + } + return tagName(tag)+"="+valuePrint; + } + public abstract String stringValue(); } public static class Utf8Entry extends Entry { - final String value; + final String value; - Utf8Entry(String value) { - super(CONSTANT_Utf8); - this.value = value.intern(); - hashCode(); // force computation of valueHash - } - protected int computeValueHash() { - return value.hashCode(); - } - public boolean equals(Object o) { - if (!sameTagAs(o)) return false; - // Use reference equality of interned strings: - return ((Utf8Entry)o).value == value; - } - public int compareTo(Object o) { - int x = superCompareTo(o); - if (x == 0) { - x = value.compareTo(((Utf8Entry)o).value); - } - return x; - } - public String stringValue() { - return value; - } + Utf8Entry(String value) { + super(CONSTANT_Utf8); + this.value = value.intern(); + hashCode(); // force computation of valueHash + } + protected int computeValueHash() { + return value.hashCode(); + } + public boolean equals(Object o) { + if (!sameTagAs(o)) return false; + // Use reference equality of interned strings: + return ((Utf8Entry)o).value == value; + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + x = value.compareTo(((Utf8Entry)o).value); + } + return x; + } + public String stringValue() { + return value; + } } static boolean isMemberTag(byte tag) { - switch (tag) { - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - return true; - } - return false; + switch (tag) { + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + return true; + } + return false; } static byte numberTagOf(Number value) { - if (value instanceof Integer) return CONSTANT_Integer; - if (value instanceof Float) return CONSTANT_Float; - if (value instanceof Long) return CONSTANT_Long; - if (value instanceof Double) return CONSTANT_Double; - throw new RuntimeException("bad literal value "+value); + if (value instanceof Integer) return CONSTANT_Integer; + if (value instanceof Float) return CONSTANT_Float; + if (value instanceof Long) return CONSTANT_Long; + if (value instanceof Double) return CONSTANT_Double; + throw new RuntimeException("bad literal value "+value); } public static abstract class LiteralEntry extends Entry { - protected LiteralEntry(byte tag) { - super(tag); - } + protected LiteralEntry(byte tag) { + super(tag); + } - public abstract Comparable literalValue(); + public abstract Comparable literalValue(); } public static class NumberEntry extends LiteralEntry { - final Number value; - NumberEntry(Number value) { - super(numberTagOf(value)); - this.value = value; - hashCode(); // force computation of valueHash - } - protected int computeValueHash() { - return value.hashCode(); - } + final Number value; + NumberEntry(Number value) { + super(numberTagOf(value)); + this.value = value; + hashCode(); // force computation of valueHash + } + protected int computeValueHash() { + return value.hashCode(); + } - public boolean equals(Object o) { - if (!sameTagAs(o)) return false; - return (((NumberEntry)o).value).equals(value); - } - public int compareTo(Object o) { - int x = superCompareTo(o); - if (x == 0) { - x = ((Comparable)value).compareTo(((NumberEntry)o).value); - } - return x; - } - public Number numberValue() { - return value; - } - public Comparable literalValue() { - return (Comparable) value; - } - public String stringValue() { - return value.toString(); - } + public boolean equals(Object o) { + if (!sameTagAs(o)) return false; + return (((NumberEntry)o).value).equals(value); + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + x = ((Comparable)value).compareTo(((NumberEntry)o).value); + } + return x; + } + public Number numberValue() { + return value; + } + public Comparable literalValue() { + return (Comparable) value; + } + public String stringValue() { + return value.toString(); + } } public static class StringEntry extends LiteralEntry { - final Utf8Entry ref; - public Entry getRef(int i) { return i == 0 ? ref : null; } + final Utf8Entry ref; + public Entry getRef(int i) { return i == 0 ? ref : null; } - StringEntry(Entry ref) { - super(CONSTANT_String); - this.ref = (Utf8Entry) ref; - hashCode(); // force computation of valueHash - } - protected int computeValueHash() { - return ref.hashCode() + tag; - } - public boolean equals(Object o) { - if (!sameTagAs(o)) return false; - return ((StringEntry)o).ref.eq(ref); - } - public int compareTo(Object o) { - int x = superCompareTo(o); - if (x == 0) { - x = ref.compareTo(((StringEntry)o).ref); - } - return x; - } - public Comparable literalValue() { - return ref.stringValue(); - } - public String stringValue() { - return ref.stringValue(); - } + StringEntry(Entry ref) { + super(CONSTANT_String); + this.ref = (Utf8Entry) ref; + hashCode(); // force computation of valueHash + } + protected int computeValueHash() { + return ref.hashCode() + tag; + } + public boolean equals(Object o) { + if (!sameTagAs(o)) return false; + return ((StringEntry)o).ref.eq(ref); + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + x = ref.compareTo(((StringEntry)o).ref); + } + return x; + } + public Comparable literalValue() { + return ref.stringValue(); + } + public String stringValue() { + return ref.stringValue(); + } } public static class ClassEntry extends Entry { - final Utf8Entry ref; - public Entry getRef(int i) { return i == 0 ? ref : null; } + final Utf8Entry ref; + public Entry getRef(int i) { return i == 0 ? ref : null; } - protected int computeValueHash() { - return ref.hashCode() + tag; - } - ClassEntry(Entry ref) { - super(CONSTANT_Class); - this.ref = (Utf8Entry) ref; - hashCode(); // force computation of valueHash - } - public boolean equals(Object o) { - if (!sameTagAs(o)) return false; - return ((ClassEntry)o).ref.eq(ref); - } - public int compareTo(Object o) { - int x = superCompareTo(o); - if (x == 0) { - x = ref.compareTo(((ClassEntry)o).ref); - } - return x; - } - public String stringValue() { - return ref.stringValue(); - } + protected int computeValueHash() { + return ref.hashCode() + tag; + } + ClassEntry(Entry ref) { + super(CONSTANT_Class); + this.ref = (Utf8Entry) ref; + hashCode(); // force computation of valueHash + } + public boolean equals(Object o) { + if (!sameTagAs(o)) return false; + return ((ClassEntry)o).ref.eq(ref); + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + x = ref.compareTo(((ClassEntry)o).ref); + } + return x; + } + public String stringValue() { + return ref.stringValue(); + } } public static class DescriptorEntry extends Entry { - final Utf8Entry nameRef; - final SignatureEntry typeRef; - public Entry getRef(int i) { - if (i == 0) return nameRef; - if (i == 1) return typeRef; - return null; - } - DescriptorEntry(Entry nameRef, Entry typeRef) { - super(CONSTANT_NameandType); - if (typeRef instanceof Utf8Entry) { - typeRef = getSignatureEntry(typeRef.stringValue()); - } - this.nameRef = (Utf8Entry) nameRef; - this.typeRef = (SignatureEntry) typeRef; - hashCode(); // force computation of valueHash - } - protected int computeValueHash() { - int hc2 = typeRef.hashCode(); - return (nameRef.hashCode() + (hc2 << 8)) ^ hc2; - } - public boolean equals(Object o) { - if (!sameTagAs(o)) return false; - DescriptorEntry that = (DescriptorEntry)o; - return this.nameRef.eq(that.nameRef) - && this.typeRef.eq(that.typeRef); - } - public int compareTo(Object o) { - int x = superCompareTo(o); - if (x == 0) { - DescriptorEntry that = (DescriptorEntry)o; - // Primary key is typeRef, not nameRef. - x = this.typeRef.compareTo(that.typeRef); - if (x == 0) - x = this.nameRef.compareTo(that.nameRef); - } - return x; - } - public String stringValue() { - return stringValueOf(nameRef, typeRef); - } - static - String stringValueOf(Entry nameRef, Entry typeRef) { - return typeRef.stringValue()+","+nameRef.stringValue(); - } + final Utf8Entry nameRef; + final SignatureEntry typeRef; + public Entry getRef(int i) { + if (i == 0) return nameRef; + if (i == 1) return typeRef; + return null; + } + DescriptorEntry(Entry nameRef, Entry typeRef) { + super(CONSTANT_NameandType); + if (typeRef instanceof Utf8Entry) { + typeRef = getSignatureEntry(typeRef.stringValue()); + } + this.nameRef = (Utf8Entry) nameRef; + this.typeRef = (SignatureEntry) typeRef; + hashCode(); // force computation of valueHash + } + protected int computeValueHash() { + int hc2 = typeRef.hashCode(); + return (nameRef.hashCode() + (hc2 << 8)) ^ hc2; + } + public boolean equals(Object o) { + if (!sameTagAs(o)) return false; + DescriptorEntry that = (DescriptorEntry)o; + return this.nameRef.eq(that.nameRef) + && this.typeRef.eq(that.typeRef); + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + DescriptorEntry that = (DescriptorEntry)o; + // Primary key is typeRef, not nameRef. + x = this.typeRef.compareTo(that.typeRef); + if (x == 0) + x = this.nameRef.compareTo(that.nameRef); + } + return x; + } + public String stringValue() { + return stringValueOf(nameRef, typeRef); + } + static + String stringValueOf(Entry nameRef, Entry typeRef) { + return typeRef.stringValue()+","+nameRef.stringValue(); + } - public String prettyString() { - return nameRef.stringValue()+typeRef.prettyString(); - } + public String prettyString() { + return nameRef.stringValue()+typeRef.prettyString(); + } - public boolean isMethod() { - return typeRef.isMethod(); - } + public boolean isMethod() { + return typeRef.isMethod(); + } - public byte getLiteralTag() { - return typeRef.getLiteralTag(); - } + public byte getLiteralTag() { + return typeRef.getLiteralTag(); + } } public static class MemberEntry extends Entry { - final ClassEntry classRef; - final DescriptorEntry descRef; - public Entry getRef(int i) { - if (i == 0) return classRef; - if (i == 1) return descRef; - return null; - } - protected int computeValueHash() { - int hc2 = descRef.hashCode(); - return (classRef.hashCode() + (hc2 << 8)) ^ hc2; - } + final ClassEntry classRef; + final DescriptorEntry descRef; + public Entry getRef(int i) { + if (i == 0) return classRef; + if (i == 1) return descRef; + return null; + } + protected int computeValueHash() { + int hc2 = descRef.hashCode(); + return (classRef.hashCode() + (hc2 << 8)) ^ hc2; + } - MemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) { - super(tag); - assert(isMemberTag(tag)); - this.classRef = classRef; - this.descRef = descRef; - hashCode(); // force computation of valueHash - } - public boolean equals(Object o) { - if (!sameTagAs(o)) return false; - MemberEntry that = (MemberEntry)o; - return this.classRef.eq(that.classRef) - && this.descRef.eq(that.descRef); - } - public int compareTo(Object o) { - int x = superCompareTo(o); - if (x == 0) { - MemberEntry that = (MemberEntry)o; - // Primary key is classRef. - x = this.classRef.compareTo(that.classRef); - if (x == 0) - x = this.descRef.compareTo(that.descRef); - } - return x; - } - public String stringValue() { - return stringValueOf(tag, classRef, descRef); - } - static - String stringValueOf(byte tag, ClassEntry classRef, DescriptorEntry descRef) { - assert(isMemberTag(tag)); - String pfx; - switch (tag) { - case CONSTANT_Fieldref: pfx = "Field:"; break; - case CONSTANT_Methodref: pfx = "Method:"; break; - case CONSTANT_InterfaceMethodref: pfx = "IMethod:"; break; - default: pfx = tag+"???"; break; - } - return pfx+classRef.stringValue()+","+descRef.stringValue(); - } + MemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) { + super(tag); + assert(isMemberTag(tag)); + this.classRef = classRef; + this.descRef = descRef; + hashCode(); // force computation of valueHash + } + public boolean equals(Object o) { + if (!sameTagAs(o)) return false; + MemberEntry that = (MemberEntry)o; + return this.classRef.eq(that.classRef) + && this.descRef.eq(that.descRef); + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + MemberEntry that = (MemberEntry)o; + // Primary key is classRef. + x = this.classRef.compareTo(that.classRef); + if (x == 0) + x = this.descRef.compareTo(that.descRef); + } + return x; + } + public String stringValue() { + return stringValueOf(tag, classRef, descRef); + } + static + String stringValueOf(byte tag, ClassEntry classRef, DescriptorEntry descRef) { + assert(isMemberTag(tag)); + String pfx; + switch (tag) { + case CONSTANT_Fieldref: pfx = "Field:"; break; + case CONSTANT_Methodref: pfx = "Method:"; break; + case CONSTANT_InterfaceMethodref: pfx = "IMethod:"; break; + default: pfx = tag+"???"; break; + } + return pfx+classRef.stringValue()+","+descRef.stringValue(); + } - public boolean isMethod() { - return descRef.isMethod(); - } + public boolean isMethod() { + return descRef.isMethod(); + } } public static class SignatureEntry extends Entry { - final Utf8Entry formRef; - final ClassEntry[] classRefs; - String value; - Utf8Entry asUtf8Entry; - public Entry getRef(int i) { - if (i == 0) return formRef; - return i-1 < classRefs.length ? classRefs[i-1] : null; - } - SignatureEntry(String value) { - super(CONSTANT_Signature); - value = value.intern(); // always do this - this.value = value; - String[] parts = structureSignature(value); - formRef = getUtf8Entry(parts[0]); - classRefs = new ClassEntry[parts.length-1]; - for (int i = 1; i < parts.length; i++) - classRefs[i-1] = getClassEntry(parts[i]); - hashCode(); // force computation of valueHash - } - protected int computeValueHash() { - stringValue(); // force computation of value - return value.hashCode() + tag; - } + final Utf8Entry formRef; + final ClassEntry[] classRefs; + String value; + Utf8Entry asUtf8Entry; + public Entry getRef(int i) { + if (i == 0) return formRef; + return i-1 < classRefs.length ? classRefs[i-1] : null; + } + SignatureEntry(String value) { + super(CONSTANT_Signature); + value = value.intern(); // always do this + this.value = value; + String[] parts = structureSignature(value); + formRef = getUtf8Entry(parts[0]); + classRefs = new ClassEntry[parts.length-1]; + for (int i = 1; i < parts.length; i++) + classRefs[i-1] = getClassEntry(parts[i]); + hashCode(); // force computation of valueHash + } + protected int computeValueHash() { + stringValue(); // force computation of value + return value.hashCode() + tag; + } - public Utf8Entry asUtf8Entry() { - if (asUtf8Entry == null) { - asUtf8Entry = getUtf8Entry(stringValue()); - } - return asUtf8Entry; - } + public Utf8Entry asUtf8Entry() { + if (asUtf8Entry == null) { + asUtf8Entry = getUtf8Entry(stringValue()); + } + return asUtf8Entry; + } - public boolean equals(Object o) { - if (!sameTagAs(o)) return false; - return ((SignatureEntry)o).value == value; - } - public int compareTo(Object o) { - int x = superCompareTo(o); - if (x == 0) { - SignatureEntry that = (SignatureEntry)o; - x = compareSignatures(this.value, that.value); - } - return x; - } - public String stringValue() { - if (value == null) { - value = stringValueOf(formRef, classRefs); - } - return value; - } - static - String stringValueOf(Utf8Entry formRef, ClassEntry[] classRefs) { - String[] parts = new String[1+classRefs.length]; - parts[0] = formRef.stringValue(); - for (int i = 1; i < parts.length; i++) - parts[i] = classRefs[i-1].stringValue(); - return flattenSignature(parts).intern(); - } + public boolean equals(Object o) { + if (!sameTagAs(o)) return false; + return ((SignatureEntry)o).value == value; + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + SignatureEntry that = (SignatureEntry)o; + x = compareSignatures(this.value, that.value); + } + return x; + } + public String stringValue() { + if (value == null) { + value = stringValueOf(formRef, classRefs); + } + return value; + } + static + String stringValueOf(Utf8Entry formRef, ClassEntry[] classRefs) { + String[] parts = new String[1+classRefs.length]; + parts[0] = formRef.stringValue(); + for (int i = 1; i < parts.length; i++) + parts[i] = classRefs[i-1].stringValue(); + return flattenSignature(parts).intern(); + } - public int computeSize(boolean countDoublesTwice) { - String form = formRef.stringValue(); - int min = 0; - int max = 1; - if (isMethod()) { - min = 1; - max = form.indexOf(')'); - } - int size = 0; - for (int i = min; i < max; i++) { - switch (form.charAt(i)) { - case 'D': - case 'J': - if (countDoublesTwice) size++; - break; - case '[': - // Skip rest of array info. - while (form.charAt(i) == '[') ++i; - break; - case ';': - continue; - default: - assert(0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i))); - break; - } - size++; - } - return size; - } - public boolean isMethod() { - return formRef.stringValue().charAt(0) == '('; - } - public byte getLiteralTag() { - switch (formRef.stringValue().charAt(0)) { - case 'L': return CONSTANT_String; - case 'I': return CONSTANT_Integer; - case 'J': return CONSTANT_Long; - case 'F': return CONSTANT_Float; - case 'D': return CONSTANT_Double; - case 'B': case 'S': case 'C': case 'Z': - return CONSTANT_Integer; - } - assert(false); - return CONSTANT_None; - } - public String prettyString() { - String s; - if (isMethod()) { - s = formRef.stringValue(); - s = s.substring(0, 1+s.indexOf(')')); - } else { - s = "/" + formRef.stringValue(); - } - int i; - while ((i = s.indexOf(';')) >= 0) - s = s.substring(0,i) + s.substring(i+1); - return s; - } + public int computeSize(boolean countDoublesTwice) { + String form = formRef.stringValue(); + int min = 0; + int max = 1; + if (isMethod()) { + min = 1; + max = form.indexOf(')'); + } + int size = 0; + for (int i = min; i < max; i++) { + switch (form.charAt(i)) { + case 'D': + case 'J': + if (countDoublesTwice) size++; + break; + case '[': + // Skip rest of array info. + while (form.charAt(i) == '[') ++i; + break; + case ';': + continue; + default: + assert(0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i))); + break; + } + size++; + } + return size; + } + public boolean isMethod() { + return formRef.stringValue().charAt(0) == '('; + } + public byte getLiteralTag() { + switch (formRef.stringValue().charAt(0)) { + case 'L': return CONSTANT_String; + case 'I': return CONSTANT_Integer; + case 'J': return CONSTANT_Long; + case 'F': return CONSTANT_Float; + case 'D': return CONSTANT_Double; + case 'B': case 'S': case 'C': case 'Z': + return CONSTANT_Integer; + } + assert(false); + return CONSTANT_None; + } + public String prettyString() { + String s; + if (isMethod()) { + s = formRef.stringValue(); + s = s.substring(0, 1+s.indexOf(')')); + } else { + s = "/" + formRef.stringValue(); + } + int i; + while ((i = s.indexOf(';')) >= 0) + s = s.substring(0,i) + s.substring(i+1); + return s; + } } static int compareSignatures(String s1, String s2) { - return compareSignatures(s1, s2, null, null); + return compareSignatures(s1, s2, null, null); } static int compareSignatures(String s1, String s2, String[] p1, String[] p2) { - final int S1_COMES_FIRST = -1; - final int S2_COMES_FIRST = +1; - char c1 = s1.charAt(0); - char c2 = s2.charAt(0); - // fields before methods (because there are fewer of them) - if (c1 != '(' && c2 == '(') return S1_COMES_FIRST; - if (c2 != '(' && c1 == '(') return S2_COMES_FIRST; - if (p1 == null) p1 = structureSignature(s1); - if (p2 == null) p2 = structureSignature(s2); - /* - // non-classes before classes (because there are fewer of them) - if (p1.length == 1 && p2.length > 1) return S1_COMES_FIRST; - if (p2.length == 1 && p1.length > 1) return S2_COMES_FIRST; - // all else being equal, use the same comparison as for Utf8 strings - return s1.compareTo(s2); - */ - if (p1.length != p2.length) return p1.length - p2.length; - int length = p1.length; - for (int i = length; --i >= 0; ) { - int res = p1[i].compareTo(p2[i]); - if (res != 0) return res; - } - assert(s1.equals(s2)); - return 0; + final int S1_COMES_FIRST = -1; + final int S2_COMES_FIRST = +1; + char c1 = s1.charAt(0); + char c2 = s2.charAt(0); + // fields before methods (because there are fewer of them) + if (c1 != '(' && c2 == '(') return S1_COMES_FIRST; + if (c2 != '(' && c1 == '(') return S2_COMES_FIRST; + if (p1 == null) p1 = structureSignature(s1); + if (p2 == null) p2 = structureSignature(s2); + /* + // non-classes before classes (because there are fewer of them) + if (p1.length == 1 && p2.length > 1) return S1_COMES_FIRST; + if (p2.length == 1 && p1.length > 1) return S2_COMES_FIRST; + // all else being equal, use the same comparison as for Utf8 strings + return s1.compareTo(s2); + */ + if (p1.length != p2.length) return p1.length - p2.length; + int length = p1.length; + for (int i = length; --i >= 0; ) { + int res = p1[i].compareTo(p2[i]); + if (res != 0) return res; + } + assert(s1.equals(s2)); + return 0; } static int countClassParts(Utf8Entry formRef) { - int num = 0; - String s = formRef.stringValue(); - for (int i = 0; i < s.length(); i++) { - if (s.charAt(i) == 'L') ++num; - } - return num; + int num = 0; + String s = formRef.stringValue(); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == 'L') ++num; + } + return num; } static String flattenSignature(String[] parts) { - String form = parts[0]; - if (parts.length == 1) return form; - int len = form.length(); - for (int i = 1; i < parts.length; i++) { - len += parts[i].length(); - } - char[] sig = new char[len]; - int j = 0; - int k = 1; - for (int i = 0; i < form.length(); i++) { - char ch = form.charAt(i); - sig[j++] = ch; - if (ch == 'L') { - String cls = parts[k++]; - cls.getChars(0, cls.length(), sig, j); - j += cls.length(); - //sig[j++] = ';'; - } - } - assert(j == len); - assert(k == parts.length); - return new String(sig); + String form = parts[0]; + if (parts.length == 1) return form; + int len = form.length(); + for (int i = 1; i < parts.length; i++) { + len += parts[i].length(); + } + char[] sig = new char[len]; + int j = 0; + int k = 1; + for (int i = 0; i < form.length(); i++) { + char ch = form.charAt(i); + sig[j++] = ch; + if (ch == 'L') { + String cls = parts[k++]; + cls.getChars(0, cls.length(), sig, j); + j += cls.length(); + //sig[j++] = ';'; + } + } + assert(j == len); + assert(k == parts.length); + return new String(sig); } static private int skipClassNameChars(String sig, int i) { - int len = sig.length(); - for (; i < len; i++) { - char ch = sig.charAt(i); - if (ch <= ' ') break; - if (ch >= ';' && ch <= '@') break; - } - return i; + int len = sig.length(); + for (; i < len; i++) { + char ch = sig.charAt(i); + if (ch <= ' ') break; + if (ch >= ';' && ch <= '@') break; + } + return i; } static String[] structureSignature(String sig) { - sig = sig.intern(); + sig = sig.intern(); - int formLen = 0; - int nparts = 1; - for (int i = 0; i < sig.length(); i++) { - char ch = sig.charAt(i); - formLen++; - if (ch == 'L') { - nparts++; - int i2 = skipClassNameChars(sig, i+1); - i = i2-1; // keep the semicolon in the form - int i3 = sig.indexOf('<', i+1); - if (i3 > 0 && i3 < i2) - i = i3-1; - } - } - char[] form = new char[formLen]; - if (nparts == 1) { - String[] parts = { sig }; - return parts; - } - String[] parts = new String[nparts]; - int j = 0; - int k = 1; - for (int i = 0; i < sig.length(); i++) { - char ch = sig.charAt(i); - form[j++] = ch; - if (ch == 'L') { - int i2 = skipClassNameChars(sig, i+1); - parts[k++] = sig.substring(i+1, i2); - i = i2; - --i; // keep the semicolon in the form - } - } - assert(j == formLen); - assert(k == parts.length); - parts[0] = new String(form); - //assert(flattenSignature(parts).equals(sig)); - return parts; + int formLen = 0; + int nparts = 1; + for (int i = 0; i < sig.length(); i++) { + char ch = sig.charAt(i); + formLen++; + if (ch == 'L') { + nparts++; + int i2 = skipClassNameChars(sig, i+1); + i = i2-1; // keep the semicolon in the form + int i3 = sig.indexOf('<', i+1); + if (i3 > 0 && i3 < i2) + i = i3-1; + } + } + char[] form = new char[formLen]; + if (nparts == 1) { + String[] parts = { sig }; + return parts; + } + String[] parts = new String[nparts]; + int j = 0; + int k = 1; + for (int i = 0; i < sig.length(); i++) { + char ch = sig.charAt(i); + form[j++] = ch; + if (ch == 'L') { + int i2 = skipClassNameChars(sig, i+1); + parts[k++] = sig.substring(i+1, i2); + i = i2; + --i; // keep the semicolon in the form + } + } + assert(j == formLen); + assert(k == parts.length); + parts[0] = new String(form); + //assert(flattenSignature(parts).equals(sig)); + return parts; } // Handy constants: @@ -715,182 +715,182 @@ class ConstantPool implements Constants /** An Index is a mapping between CP entries and small integers. */ public static class Index extends AbstractList { - protected String debugName; - protected Entry[] cpMap; - protected boolean flattenSigs; - protected Entry[] getMap() { - return cpMap; - } - protected Index(String debugName) { - this.debugName = debugName; - } - protected Index(String debugName, Entry[] cpMap) { - this(debugName); - setMap(cpMap); - } - protected void setMap(Entry[] cpMap) { - clearIndex(); - this.cpMap = cpMap; - } - protected Index(String debugName, Collection cpMapList) { - this(debugName); - setMap(cpMapList); - } - protected void setMap(Collection cpMapList) { - cpMap = new Entry[cpMapList.size()]; - cpMapList.toArray(cpMap); - setMap(cpMap); - } - public int size() { - return cpMap.length; - } - public Object get(int i) { - return cpMap[i]; - } - public Entry getEntry(int i) { - // same as get(), with covariant return type - return cpMap[i]; - } + protected String debugName; + protected Entry[] cpMap; + protected boolean flattenSigs; + protected Entry[] getMap() { + return cpMap; + } + protected Index(String debugName) { + this.debugName = debugName; + } + protected Index(String debugName, Entry[] cpMap) { + this(debugName); + setMap(cpMap); + } + protected void setMap(Entry[] cpMap) { + clearIndex(); + this.cpMap = cpMap; + } + protected Index(String debugName, Collection cpMapList) { + this(debugName); + setMap(cpMapList); + } + protected void setMap(Collection cpMapList) { + cpMap = new Entry[cpMapList.size()]; + cpMapList.toArray(cpMap); + setMap(cpMap); + } + public int size() { + return cpMap.length; + } + public Object get(int i) { + return cpMap[i]; + } + public Entry getEntry(int i) { + // same as get(), with covariant return type + return cpMap[i]; + } - // Find index of e in cpMap, or return -1 if none. - // - // As a special hack, if flattenSigs, signatures are - // treated as equivalent entries of cpMap. This is wrong - // fron a Collection point of view, because contains() - // reports true for signatures, but the iterator() - // never produces them! - private int findIndexOf(Entry e) { - if (indexKey == null) initializeIndex(); - int probe = findIndexLocation(e); - if (indexKey[probe] != e) { - if (flattenSigs && e.tag == CONSTANT_Signature) { - SignatureEntry se = (SignatureEntry) e; - return findIndexOf(se.asUtf8Entry()); - } - return -1; - } - int index = indexValue[probe]; - assert(e.equals(cpMap[index])); - return index; - } - public boolean contains(Entry e) { - return findIndexOf(e) >= 0; - } - // Find index of e in cpMap. Should not return -1. - public int indexOf(Entry e) { - int index = findIndexOf(e); - if (index < 0 && verbose() > 0) { - System.out.println("not found: "+e); - System.out.println(" in: "+this.dumpString()); - Thread.dumpStack(); - } - assert(index >= 0); - return index; - } - public boolean contains(Object e) { - return findIndexOf((Entry)e) >= 0; - } - public int indexOf(Object e) { - return findIndexOf((Entry)e); - } - public int lastIndexOf(Object e) { - return indexOf(e); - } + // Find index of e in cpMap, or return -1 if none. + // + // As a special hack, if flattenSigs, signatures are + // treated as equivalent entries of cpMap. This is wrong + // fron a Collection point of view, because contains() + // reports true for signatures, but the iterator() + // never produces them! + private int findIndexOf(Entry e) { + if (indexKey == null) initializeIndex(); + int probe = findIndexLocation(e); + if (indexKey[probe] != e) { + if (flattenSigs && e.tag == CONSTANT_Signature) { + SignatureEntry se = (SignatureEntry) e; + return findIndexOf(se.asUtf8Entry()); + } + return -1; + } + int index = indexValue[probe]; + assert(e.equals(cpMap[index])); + return index; + } + public boolean contains(Entry e) { + return findIndexOf(e) >= 0; + } + // Find index of e in cpMap. Should not return -1. + public int indexOf(Entry e) { + int index = findIndexOf(e); + if (index < 0 && verbose() > 0) { + System.out.println("not found: "+e); + System.out.println(" in: "+this.dumpString()); + Thread.dumpStack(); + } + assert(index >= 0); + return index; + } + public boolean contains(Object e) { + return findIndexOf((Entry)e) >= 0; + } + public int indexOf(Object e) { + return findIndexOf((Entry)e); + } + public int lastIndexOf(Object e) { + return indexOf(e); + } - public boolean assertIsSorted() { - for (int i = 1; i < cpMap.length; i++) { - if (cpMap[i-1].compareTo(cpMap[i]) > 0) { - System.out.println("Not sorted at "+(i-1)+"/"+i+": "+this.dumpString()); - return false; - } - } - return true; - } + public boolean assertIsSorted() { + for (int i = 1; i < cpMap.length; i++) { + if (cpMap[i-1].compareTo(cpMap[i]) > 0) { + System.out.println("Not sorted at "+(i-1)+"/"+i+": "+this.dumpString()); + return false; + } + } + return true; + } - // internal hash table - protected Entry[] indexKey; - protected int[] indexValue; - protected void clearIndex() { - indexKey = null; - indexValue = null; - } - private int findIndexLocation(Entry e) { - int size = indexKey.length; - int hash = e.hashCode(); - int probe = hash & (size - 1); - int stride = ((hash >>> 8) | 1) & (size - 1); - for (;;) { - Entry e1 = indexKey[probe]; - if (e1 == e || e1 == null) - return probe; - probe += stride; - if (probe >= size) probe -= size; - } - } - private void initializeIndex() { - if (verbose() > 2) - System.out.println("initialize Index "+debugName+" ["+size()+"]"); - int hsize0 = (int)((cpMap.length + 10) * 1.5); - int hsize = 1; - while (hsize < hsize0) hsize <<= 1; - indexKey = new Entry[hsize]; - indexValue = new int[hsize]; - for (int i = 0; i < cpMap.length; i++) { - Entry e = cpMap[i]; - if (e == null) continue; - int probe = findIndexLocation(e); - assert(indexKey[probe] == null); // e has unique index - indexKey[probe] = e; - indexValue[probe] = i; - } - } - public Object[] toArray(Object[] a) { - int sz = size(); - if (a.length < sz) return super.toArray(a); - System.arraycopy(cpMap, 0, a, 0, sz); - if (a.length > sz) a[sz] = null; - return a; - } - public Object[] toArray() { - return toArray(new Entry[size()]); - } - public Object clone() { - return new Index(debugName, (Entry[]) cpMap.clone()); - } - public String toString() { - return "Index "+debugName+" ["+size()+"]"; - } - public String dumpString() { - String s = toString(); - s += " {\n"; - for (int i = 0; i < cpMap.length; i++) { - s += " "+i+": "+cpMap[i]+"\n"; - } - s += "}"; - return s; - } + // internal hash table + protected Entry[] indexKey; + protected int[] indexValue; + protected void clearIndex() { + indexKey = null; + indexValue = null; + } + private int findIndexLocation(Entry e) { + int size = indexKey.length; + int hash = e.hashCode(); + int probe = hash & (size - 1); + int stride = ((hash >>> 8) | 1) & (size - 1); + for (;;) { + Entry e1 = indexKey[probe]; + if (e1 == e || e1 == null) + return probe; + probe += stride; + if (probe >= size) probe -= size; + } + } + private void initializeIndex() { + if (verbose() > 2) + System.out.println("initialize Index "+debugName+" ["+size()+"]"); + int hsize0 = (int)((cpMap.length + 10) * 1.5); + int hsize = 1; + while (hsize < hsize0) hsize <<= 1; + indexKey = new Entry[hsize]; + indexValue = new int[hsize]; + for (int i = 0; i < cpMap.length; i++) { + Entry e = cpMap[i]; + if (e == null) continue; + int probe = findIndexLocation(e); + assert(indexKey[probe] == null); // e has unique index + indexKey[probe] = e; + indexValue[probe] = i; + } + } + public Object[] toArray(Object[] a) { + int sz = size(); + if (a.length < sz) return super.toArray(a); + System.arraycopy(cpMap, 0, a, 0, sz); + if (a.length > sz) a[sz] = null; + return a; + } + public Object[] toArray() { + return toArray(new Entry[size()]); + } + public Object clone() { + return new Index(debugName, (Entry[]) cpMap.clone()); + } + public String toString() { + return "Index "+debugName+" ["+size()+"]"; + } + public String dumpString() { + String s = toString(); + s += " {\n"; + for (int i = 0; i < cpMap.length; i++) { + s += " "+i+": "+cpMap[i]+"\n"; + } + s += "}"; + return s; + } } // Index methods. public static Index makeIndex(String debugName, Entry[] cpMap) { - return new Index(debugName, cpMap); + return new Index(debugName, cpMap); } public static Index makeIndex(String debugName, Collection cpMapList) { - return new Index(debugName, cpMapList); + return new Index(debugName, cpMapList); } /** Sort this index (destructively) into canonical order. */ public static void sort(Index ix) { - // %%% Should move this into class Index. - ix.clearIndex(); - Arrays.sort(ix.cpMap); - if (verbose() > 2) - System.out.println("sorted "+ix.dumpString()); + // %%% Should move this into class Index. + ix.clearIndex(); + Arrays.sort(ix.cpMap); + if (verbose() > 2) + System.out.println("sorted "+ix.dumpString()); } /** Return a set of indexes partitioning these entries. @@ -900,210 +900,212 @@ class ConstantPool implements Constants */ public static Index[] partition(Index ix, int[] keys) { - // %%% Should move this into class Index. - ArrayList parts = new ArrayList(); - Entry[] cpMap = ix.cpMap; - assert(keys.length == cpMap.length); - for (int i = 0; i < keys.length; i++) { - int key = keys[i]; - if (key < 0) continue; - while (key >= parts.size()) parts.add(null); - ArrayList part = (ArrayList) parts.get(key); - if (part == null) { - parts.set(key, part = new ArrayList()); - } - part.add(cpMap[i]); - } - Index[] indexes = new Index[parts.size()]; - for (int key = 0; key < indexes.length; key++) { - ArrayList part = (ArrayList) parts.get(key); - if (part == null) continue; - indexes[key] = new Index(ix.debugName+"/part#"+key, part); - assert(indexes[key].indexOf(part.get(0)) == 0); - } - return indexes; + // %%% Should move this into class Index. + ArrayList parts = new ArrayList(); + Entry[] cpMap = ix.cpMap; + assert(keys.length == cpMap.length); + for (int i = 0; i < keys.length; i++) { + int key = keys[i]; + if (key < 0) continue; + while (key >= parts.size()) parts.add(null); + ArrayList part = (ArrayList) parts.get(key); + if (part == null) { + parts.set(key, part = new ArrayList()); + } + part.add(cpMap[i]); + } + Index[] indexes = new Index[parts.size()]; + for (int key = 0; key < indexes.length; key++) { + ArrayList part = (ArrayList) parts.get(key); + if (part == null) continue; + indexes[key] = new Index(ix.debugName+"/part#"+key, part); + assert(indexes[key].indexOf(part.get(0)) == 0); + } + return indexes; } public static Index[] partitionByTag(Index ix) { - // Partition by tag. - Entry[] cpMap = ix.cpMap; - int[] keys = new int[cpMap.length]; - for (int i = 0; i < keys.length; i++) { - Entry e = cpMap[i]; - keys[i] = (e == null)? -1: e.tag; - } - Index[] byTag = partition(ix, keys); - for (int tag = 0; tag < byTag.length; tag++) { - if (byTag[tag] == null) continue; - byTag[tag].debugName = tagName(tag); - } - if (byTag.length < CONSTANT_Limit) { - Index[] longer = new Index[CONSTANT_Limit]; - System.arraycopy(byTag, 0, longer, 0, byTag.length); - byTag = longer; - } - return byTag; + // Partition by tag. + Entry[] cpMap = ix.cpMap; + int[] keys = new int[cpMap.length]; + for (int i = 0; i < keys.length; i++) { + Entry e = cpMap[i]; + keys[i] = (e == null)? -1: e.tag; + } + Index[] byTag = partition(ix, keys); + for (int tag = 0; tag < byTag.length; tag++) { + if (byTag[tag] == null) continue; + byTag[tag].debugName = tagName(tag); + } + if (byTag.length < CONSTANT_Limit) { + Index[] longer = new Index[CONSTANT_Limit]; + System.arraycopy(byTag, 0, longer, 0, byTag.length); + byTag = longer; + } + return byTag; } /** Coherent group of constant pool indexes. */ public static class IndexGroup { - private Index indexUntyped; - private Index[] indexByTag = new Index[CONSTANT_Limit]; - private int[] untypedFirstIndexByTag; - private int totalSize; - private Index[][] indexByTagAndClass; + private Index indexUntyped; + private Index[] indexByTag = new Index[CONSTANT_Limit]; + private int[] untypedFirstIndexByTag; + private int totalSize; + private Index[][] indexByTagAndClass; - /** Index of all CP entries of all types, in definition order. */ - public Index getUntypedIndex() { - if (indexUntyped == null) { - untypedIndexOf(null); // warm up untypedFirstIndexByTag - Entry[] cpMap = new Entry[totalSize]; - for (int tag = 0; tag < indexByTag.length; tag++) { - Index ix = indexByTag[tag]; - if (ix == null) continue; - int ixLen = ix.cpMap.length; - if (ixLen == 0) continue; - int fillp = untypedFirstIndexByTag[tag]; - assert(cpMap[fillp] == null); - assert(cpMap[fillp+ixLen-1] == null); - System.arraycopy(ix.cpMap, 0, cpMap, fillp, ixLen); - } - indexUntyped = new Index("untyped", cpMap); - } - return indexUntyped; - } + /** Index of all CP entries of all types, in definition order. */ + public Index getUntypedIndex() { + if (indexUntyped == null) { + untypedIndexOf(null); // warm up untypedFirstIndexByTag + Entry[] cpMap = new Entry[totalSize]; + for (int tag = 0; tag < indexByTag.length; tag++) { + Index ix = indexByTag[tag]; + if (ix == null) continue; + int ixLen = ix.cpMap.length; + if (ixLen == 0) continue; + int fillp = untypedFirstIndexByTag[tag]; + assert(cpMap[fillp] == null); + assert(cpMap[fillp+ixLen-1] == null); + System.arraycopy(ix.cpMap, 0, cpMap, fillp, ixLen); + } + indexUntyped = new Index("untyped", cpMap); + } + return indexUntyped; + } - public int untypedIndexOf(Entry e) { - if (untypedFirstIndexByTag == null) { - untypedFirstIndexByTag = new int[CONSTANT_Limit]; - int fillp = 0; - for (int i = 0; i < TAGS_IN_ORDER.length; i++) { - byte tag = TAGS_IN_ORDER[i]; - Index ix = indexByTag[tag]; - if (ix == null) continue; - int ixLen = ix.cpMap.length; - untypedFirstIndexByTag[tag] = fillp; - fillp += ixLen; - } - totalSize = fillp; - } - if (e == null) return -1; - int tag = e.tag; - Index ix = indexByTag[tag]; - if (ix == null) return -1; - int idx = ix.findIndexOf(e); - if (idx >= 0) - idx += untypedFirstIndexByTag[tag]; - return idx; - } + public int untypedIndexOf(Entry e) { + if (untypedFirstIndexByTag == null) { + untypedFirstIndexByTag = new int[CONSTANT_Limit]; + int fillp = 0; + for (int i = 0; i < TAGS_IN_ORDER.length; i++) { + byte tag = TAGS_IN_ORDER[i]; + Index ix = indexByTag[tag]; + if (ix == null) continue; + int ixLen = ix.cpMap.length; + untypedFirstIndexByTag[tag] = fillp; + fillp += ixLen; + } + totalSize = fillp; + } + if (e == null) return -1; + int tag = e.tag; + Index ix = indexByTag[tag]; + if (ix == null) return -1; + int idx = ix.findIndexOf(e); + if (idx >= 0) + idx += untypedFirstIndexByTag[tag]; + return idx; + } - public void initIndexByTag(byte tag, Index ix) { - assert(indexByTag[tag] == null); // do not init twice - Entry[] cpMap = ix.cpMap; - for (int i = 0; i < cpMap.length; i++) { - // It must be a homogeneous Entry set. - assert(cpMap[i].tag == tag); - } - if (tag == CONSTANT_Utf8) { - // Special case: First Utf8 must always be empty string. - assert(cpMap.length == 0 || cpMap[0].stringValue().equals("")); - } - indexByTag[tag] = ix; - // decache indexes derived from this one: - untypedFirstIndexByTag = null; - indexUntyped = null; - if (indexByTagAndClass != null) - indexByTagAndClass[tag] = null; - } + public void initIndexByTag(byte tag, Index ix) { + assert(indexByTag[tag] == null); // do not init twice + Entry[] cpMap = ix.cpMap; + for (int i = 0; i < cpMap.length; i++) { + // It must be a homogeneous Entry set. + assert(cpMap[i].tag == tag); + } + if (tag == CONSTANT_Utf8) { + // Special case: First Utf8 must always be empty string. + assert(cpMap.length == 0 || cpMap[0].stringValue().equals("")); + } + indexByTag[tag] = ix; + // decache indexes derived from this one: + untypedFirstIndexByTag = null; + indexUntyped = null; + if (indexByTagAndClass != null) + indexByTagAndClass[tag] = null; + } - /** Index of all CP entries of a given tag. */ - public Index getIndexByTag(byte tag) { - if (tag == CONSTANT_All) { - return getUntypedIndex(); - } - Index ix = indexByTag[tag]; - if (ix == null) { - // Make an empty one by default. - ix = new Index(tagName(tag), new Entry[0]); - indexByTag[tag] = ix; - } - return ix; - } + /** Index of all CP entries of a given tag. */ + public Index getIndexByTag(byte tag) { + if (tag == CONSTANT_All) { + return getUntypedIndex(); + } + Index ix = indexByTag[tag]; + if (ix == null) { + // Make an empty one by default. + ix = new Index(tagName(tag), new Entry[0]); + indexByTag[tag] = ix; + } + return ix; + } - /** Index of all CP entries of a given tag and class. */ - public Index getMemberIndex(byte tag, ClassEntry classRef) { - if (indexByTagAndClass == null) - indexByTagAndClass = new Index[CONSTANT_Limit][]; - Index allClasses = getIndexByTag(CONSTANT_Class); - Index[] perClassIndexes = indexByTagAndClass[tag]; - if (perClassIndexes == null) { - // Create the partition now. - // Divide up all entries of the given tag according to their class. - Index allMembers = getIndexByTag(tag); - int[] whichClasses = new int[allMembers.size()]; - for (int i = 0; i < whichClasses.length; i++) { - MemberEntry e = (MemberEntry) allMembers.get(i); - int whichClass = allClasses.indexOf(e.classRef); - whichClasses[i] = whichClass; - } - perClassIndexes = partition(allMembers, whichClasses); - for (int i = 0; i < perClassIndexes.length; i++) - assert(perClassIndexes[i]==null - || perClassIndexes[i].assertIsSorted()); - indexByTagAndClass[tag] = perClassIndexes; - } - int whichClass = allClasses.indexOf(classRef); - return perClassIndexes[whichClass]; - } + /** Index of all CP entries of a given tag and class. */ + public Index getMemberIndex(byte tag, ClassEntry classRef) { + if (classRef == null) + throw new RuntimeException("missing class reference for " + tagName(tag)); + if (indexByTagAndClass == null) + indexByTagAndClass = new Index[CONSTANT_Limit][]; + Index allClasses = getIndexByTag(CONSTANT_Class); + Index[] perClassIndexes = indexByTagAndClass[tag]; + if (perClassIndexes == null) { + // Create the partition now. + // Divide up all entries of the given tag according to their class. + Index allMembers = getIndexByTag(tag); + int[] whichClasses = new int[allMembers.size()]; + for (int i = 0; i < whichClasses.length; i++) { + MemberEntry e = (MemberEntry) allMembers.get(i); + int whichClass = allClasses.indexOf(e.classRef); + whichClasses[i] = whichClass; + } + perClassIndexes = partition(allMembers, whichClasses); + for (int i = 0; i < perClassIndexes.length; i++) + assert(perClassIndexes[i]==null + || perClassIndexes[i].assertIsSorted()); + indexByTagAndClass[tag] = perClassIndexes; + } + int whichClass = allClasses.indexOf(classRef); + return perClassIndexes[whichClass]; + } - // Given the sequence of all methods of the given name and class, - // produce the ordinal of this particular given overloading. - public int getOverloadingIndex(MemberEntry methodRef) { - Index ix = getMemberIndex(methodRef.tag, methodRef.classRef); - Utf8Entry nameRef = methodRef.descRef.nameRef; - int ord = 0; - for (int i = 0; i < ix.cpMap.length; i++) { - MemberEntry e = (MemberEntry) ix.cpMap[i]; - if (e.equals(methodRef)) - return ord; - if (e.descRef.nameRef.equals(nameRef)) - // Found a different overloading. Increment the ordinal. - ord++; - } - throw new RuntimeException("should not reach here"); - } + // Given the sequence of all methods of the given name and class, + // produce the ordinal of this particular given overloading. + public int getOverloadingIndex(MemberEntry methodRef) { + Index ix = getMemberIndex(methodRef.tag, methodRef.classRef); + Utf8Entry nameRef = methodRef.descRef.nameRef; + int ord = 0; + for (int i = 0; i < ix.cpMap.length; i++) { + MemberEntry e = (MemberEntry) ix.cpMap[i]; + if (e.equals(methodRef)) + return ord; + if (e.descRef.nameRef.equals(nameRef)) + // Found a different overloading. Increment the ordinal. + ord++; + } + throw new RuntimeException("should not reach here"); + } - // Inverse of getOverloadingIndex - public MemberEntry getOverloadingForIndex(byte tag, ClassEntry classRef, String name, int which) { - assert(name == name.intern()); - Index ix = getMemberIndex(tag, classRef); - int ord = 0; - for (int i = 0; i < ix.cpMap.length; i++) { - MemberEntry e = (MemberEntry) ix.cpMap[i]; - if (e.descRef.nameRef.stringValue() == name) { - if (ord == which) return e; - ord++; - } - } - throw new RuntimeException("should not reach here"); - } + // Inverse of getOverloadingIndex + public MemberEntry getOverloadingForIndex(byte tag, ClassEntry classRef, String name, int which) { + assert(name == name.intern()); + Index ix = getMemberIndex(tag, classRef); + int ord = 0; + for (int i = 0; i < ix.cpMap.length; i++) { + MemberEntry e = (MemberEntry) ix.cpMap[i]; + if (e.descRef.nameRef.stringValue() == name) { + if (ord == which) return e; + ord++; + } + } + throw new RuntimeException("should not reach here"); + } - public boolean haveNumbers() { - for (byte tag = CONSTANT_Integer; tag <= CONSTANT_Double; tag++) { - switch (tag) { - case CONSTANT_Integer: - case CONSTANT_Float: - case CONSTANT_Long: - case CONSTANT_Double: - break; - default: - assert(false); - } - if (getIndexByTag(tag).size() > 0) return true; - } - return false; - } + public boolean haveNumbers() { + for (byte tag = CONSTANT_Integer; tag <= CONSTANT_Double; tag++) { + switch (tag) { + case CONSTANT_Integer: + case CONSTANT_Float: + case CONSTANT_Long: + case CONSTANT_Double: + break; + default: + assert(false); + } + if (getIndexByTag(tag).size() > 0) return true; + } + return false; + } } @@ -1114,84 +1116,84 @@ class ConstantPool implements Constants */ public static void completeReferencesIn(Set cpRefs, boolean flattenSigs) { - cpRefs.remove(null); - for (ListIterator work = - new ArrayList(cpRefs).listIterator(cpRefs.size()); - work.hasPrevious(); ) { - Entry e = (Entry) work.previous(); - work.remove(); // pop stack - assert(e != null); - if (flattenSigs && e.tag == CONSTANT_Signature) { - SignatureEntry se = (SignatureEntry) e; - Utf8Entry ue = se.asUtf8Entry(); - // Totally replace e by se. - cpRefs.remove(se); - cpRefs.add(ue); - e = ue; // do not descend into the sig - } - // Recursively add the refs of e to cpRefs: - for (int i = 0; ; i++) { - Entry re = e.getRef(i); - if (re == null) - break; // no more refs in e - if (cpRefs.add(re)) // output the ref - work.add(re); // push stack, if a new ref - } - } + cpRefs.remove(null); + for (ListIterator work = + new ArrayList(cpRefs).listIterator(cpRefs.size()); + work.hasPrevious(); ) { + Entry e = (Entry) work.previous(); + work.remove(); // pop stack + assert(e != null); + if (flattenSigs && e.tag == CONSTANT_Signature) { + SignatureEntry se = (SignatureEntry) e; + Utf8Entry ue = se.asUtf8Entry(); + // Totally replace e by se. + cpRefs.remove(se); + cpRefs.add(ue); + e = ue; // do not descend into the sig + } + // Recursively add the refs of e to cpRefs: + for (int i = 0; ; i++) { + Entry re = e.getRef(i); + if (re == null) + break; // no more refs in e + if (cpRefs.add(re)) // output the ref + work.add(re); // push stack, if a new ref + } + } } static double percent(int num, int den) { - return (int)((10000.0*num)/den + 0.5) / 100.0; + return (int)((10000.0*num)/den + 0.5) / 100.0; } public static String tagName(int tag) { - switch (tag) { - case CONSTANT_Utf8: return "Utf8"; - case CONSTANT_Integer: return "Integer"; - case CONSTANT_Float: return "Float"; - case CONSTANT_Long: return "Long"; - case CONSTANT_Double: return "Double"; - case CONSTANT_Class: return "Class"; - case CONSTANT_String: return "String"; - case CONSTANT_Fieldref: return "Fieldref"; - case CONSTANT_Methodref: return "Methodref"; - case CONSTANT_InterfaceMethodref: return "InterfaceMethodref"; - case CONSTANT_NameandType: return "NameandType"; + switch (tag) { + case CONSTANT_Utf8: return "Utf8"; + case CONSTANT_Integer: return "Integer"; + case CONSTANT_Float: return "Float"; + case CONSTANT_Long: return "Long"; + case CONSTANT_Double: return "Double"; + case CONSTANT_Class: return "Class"; + case CONSTANT_String: return "String"; + case CONSTANT_Fieldref: return "Fieldref"; + case CONSTANT_Methodref: return "Methodref"; + case CONSTANT_InterfaceMethodref: return "InterfaceMethodref"; + case CONSTANT_NameandType: return "NameandType"; - // pseudo-tags: - case CONSTANT_All: return "*All"; - case CONSTANT_None: return "*None"; - case CONSTANT_Signature: return "*Signature"; - } - return "tag#"+tag; + // pseudo-tags: + case CONSTANT_All: return "*All"; + case CONSTANT_None: return "*None"; + case CONSTANT_Signature: return "*Signature"; + } + return "tag#"+tag; } // archive constant pool definition order static final byte TAGS_IN_ORDER[] = { - CONSTANT_Utf8, - CONSTANT_Integer, // cp_Int - CONSTANT_Float, - CONSTANT_Long, - CONSTANT_Double, - CONSTANT_String, - CONSTANT_Class, - CONSTANT_Signature, - CONSTANT_NameandType, // cp_Descr - CONSTANT_Fieldref, // cp_Field - CONSTANT_Methodref, // cp_Method - CONSTANT_InterfaceMethodref // cp_Imethod + CONSTANT_Utf8, + CONSTANT_Integer, // cp_Int + CONSTANT_Float, + CONSTANT_Long, + CONSTANT_Double, + CONSTANT_String, + CONSTANT_Class, + CONSTANT_Signature, + CONSTANT_NameandType, // cp_Descr + CONSTANT_Fieldref, // cp_Field + CONSTANT_Methodref, // cp_Method + CONSTANT_InterfaceMethodref // cp_Imethod }; static final byte TAG_ORDER[]; static { - TAG_ORDER = new byte[CONSTANT_Limit]; - for (int i = 0; i < TAGS_IN_ORDER.length; i++) { - TAG_ORDER[TAGS_IN_ORDER[i]] = (byte)(i+1); - } - /* - System.out.println("TAG_ORDER[] = {"); - for (int i = 0; i < TAG_ORDER.length; i++) - System.out.println(" "+TAG_ORDER[i]+","); - System.out.println("};"); - */ + TAG_ORDER = new byte[CONSTANT_Limit]; + for (int i = 0; i < TAGS_IN_ORDER.length; i++) { + TAG_ORDER[TAGS_IN_ORDER[i]] = (byte)(i+1); + } + /* + System.out.println("TAG_ORDER[] = {"); + for (int i = 0; i < TAG_ORDER.length; i++) + System.out.println(" "+TAG_ORDER[i]+","); + System.out.println("};"); + */ } } diff --git a/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java b/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java --- jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java +++ jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -22,7 +22,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package com.sun.java.util.jar.pack; @@ -81,239 +80,246 @@ class NativeUnpack { private PropMap _props; static { - // If loading from stand alone build uncomment this. - // System.loadLibrary("unpack"); - java.security.AccessController.doPrivileged( - new sun.security.action.LoadLibraryAction("unpack")); - initIDs(); + // If loading from stand alone build uncomment this. + // System.loadLibrary("unpack"); + java.security.AccessController.doPrivileged( + new sun.security.action.LoadLibraryAction("unpack")); + initIDs(); } - + NativeUnpack(UnpackerImpl p200) { - super(); - _p200 = p200; - _props = p200._props; - p200._nunp = this; + super(); + _p200 = p200; + _props = p200._props; + p200._nunp = this; } // for JNI callbacks static private Object currentInstance() { - UnpackerImpl p200 = (UnpackerImpl) Utils.currentInstance.get(); - return (p200 == null)? null: p200._nunp; + UnpackerImpl p200 = (UnpackerImpl) Utils.currentInstance.get(); + return (p200 == null)? null: p200._nunp; + } + + private synchronized long getUnpackerPtr() { + return unpackerPtr; } // Callback from the unpacker engine to get more data. private long readInputFn(ByteBuffer pbuf, long minlen) throws IOException { - if (in == null) return 0; // nothing is readable - long maxlen = pbuf.capacity() - pbuf.position(); - assert(minlen <= maxlen); // don't talk nonsense - long numread = 0; - int steps = 0; - while (numread < minlen) { - steps++; - // read available input, up to buf.length or maxlen - int readlen = _buf.length; - if (readlen > (maxlen - numread)) - readlen = (int)(maxlen - numread); - int nr = in.read(_buf, 0, readlen); - if (nr <= 0) break; - numread += nr; - assert(numread <= maxlen); - // %%% get rid of this extra copy by using nio? - pbuf.put(_buf, 0, nr); - } - if (_verbose > 1) - Utils.log.fine("readInputFn("+minlen+","+maxlen+") => "+numread+" steps="+steps); - if (maxlen > 100) { - _estByteLimit = _byteCount + maxlen; - } else { - _estByteLimit = (_byteCount + numread) * 20; - } - _byteCount += numread; - updateProgress(); - return numread; + if (in == null) return 0; // nothing is readable + long maxlen = pbuf.capacity() - pbuf.position(); + assert(minlen <= maxlen); // don't talk nonsense + long numread = 0; + int steps = 0; + while (numread < minlen) { + steps++; + // read available input, up to buf.length or maxlen + int readlen = _buf.length; + if (readlen > (maxlen - numread)) + readlen = (int)(maxlen - numread); + int nr = in.read(_buf, 0, readlen); + if (nr <= 0) break; + numread += nr; + assert(numread <= maxlen); + // %%% get rid of this extra copy by using nio? + pbuf.put(_buf, 0, nr); + } + if (_verbose > 1) + Utils.log.fine("readInputFn("+minlen+","+maxlen+") => "+numread+" steps="+steps); + if (maxlen > 100) { + _estByteLimit = _byteCount + maxlen; + } else { + _estByteLimit = (_byteCount + numread) * 20; + } + _byteCount += numread; + updateProgress(); + return numread; } private void updateProgress() { - // Progress is a combination of segment reading and file writing. - final double READ_WT = 0.33; - final double WRITE_WT = 0.67; - double readProgress = _segCount; - if (_estByteLimit > 0 && _byteCount > 0) - readProgress += (double)_byteCount / _estByteLimit; - double writeProgress = _fileCount; - double scaledProgress - = READ_WT * readProgress / Math.max(_estSegLimit,1) - + WRITE_WT * writeProgress / Math.max(_estFileLimit,1); - int percent = (int) Math.round(100*scaledProgress); - if (percent > 100) percent = 100; - if (percent > _prevPercent) { - _prevPercent = percent; - _props.setInteger(Pack200.Unpacker.PROGRESS, percent); - if (_verbose > 0) - Utils.log.info("progress = "+percent); - } + // Progress is a combination of segment reading and file writing. + final double READ_WT = 0.33; + final double WRITE_WT = 0.67; + double readProgress = _segCount; + if (_estByteLimit > 0 && _byteCount > 0) + readProgress += (double)_byteCount / _estByteLimit; + double writeProgress = _fileCount; + double scaledProgress + = READ_WT * readProgress / Math.max(_estSegLimit,1) + + WRITE_WT * writeProgress / Math.max(_estFileLimit,1); + int percent = (int) Math.round(100*scaledProgress); + if (percent > 100) percent = 100; + if (percent > _prevPercent) { + _prevPercent = percent; + _props.setInteger(Pack200.Unpacker.PROGRESS, percent); + if (_verbose > 0) + Utils.log.info("progress = "+percent); + } } private void copyInOption(String opt) { - String val = _props.getProperty(opt); - if (_verbose > 0) - Utils.log.info("set "+opt+"="+val); - if (val != null) { - boolean set = setOption(opt, val); - if (!set) - Utils.log.warning("Invalid option "+opt+"="+val); - } + String val = _props.getProperty(opt); + if (_verbose > 0) + Utils.log.info("set "+opt+"="+val); + if (val != null) { + boolean set = setOption(opt, val); + if (!set) + Utils.log.warning("Invalid option "+opt+"="+val); + } } void run(InputStream inRaw, JarOutputStream jstream, - ByteBuffer presetInput) throws IOException { - BufferedInputStream in = new BufferedInputStream(inRaw); - this.in = in; // for readInputFn to see - _verbose = _props.getInteger(Utils.DEBUG_VERBOSE); - // Fix for BugId: 4902477, -unpack.modification.time = 1059010598000 + ByteBuffer presetInput) throws IOException { + BufferedInputStream in = new BufferedInputStream(inRaw); + this.in = in; // for readInputFn to see + _verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + // Fix for BugId: 4902477, -unpack.modification.time = 1059010598000 // TODO eliminate and fix in unpack.cpp + + final int modtime = Pack200.Packer.KEEP.equals(_props.getProperty(Utils.UNPACK_MODIFICATION_TIME, "0")) ? + Constants.NO_MODTIME : _props.getTime(Utils.UNPACK_MODIFICATION_TIME); - final int modtime = Pack200.Packer.KEEP.equals(_props.getProperty(Utils.UNPACK_MODIFICATION_TIME, "0")) ? - Constants.NO_MODTIME : _props.getTime(Utils.UNPACK_MODIFICATION_TIME); + copyInOption(Utils.DEBUG_VERBOSE); + copyInOption(Pack200.Unpacker.DEFLATE_HINT); + if (modtime == Constants.NO_MODTIME) // Dont pass KEEP && NOW + copyInOption(Utils.UNPACK_MODIFICATION_TIME); + updateProgress(); // reset progress bar + for (;;) { + // Read the packed bits. + long counts = start(presetInput, 0); + _byteCount = _estByteLimit = 0; // reset partial scan counts + ++_segCount; // just finished scanning a whole segment... + int nextSeg = (int)( counts >>> 32 ); + int nextFile = (int)( counts >>> 0 ); - copyInOption(Utils.DEBUG_VERBOSE); - copyInOption(Pack200.Unpacker.DEFLATE_HINT); - if (modtime == Constants.NO_MODTIME) // Dont pass KEEP && NOW - copyInOption(Utils.UNPACK_MODIFICATION_TIME); - updateProgress(); // reset progress bar - for (;;) { - // Read the packed bits. - long counts = start(presetInput, 0); - _byteCount = _estByteLimit = 0; // reset partial scan counts - ++_segCount; // just finished scanning a whole segment... - int nextSeg = (int)( counts >>> 32 ); - int nextFile = (int)( counts >>> 0 ); + // Estimate eventual total number of segments and files. + _estSegLimit = _segCount + nextSeg; + double filesAfterThisSeg = _fileCount + nextFile; + _estFileLimit = (int)( (filesAfterThisSeg * + _estSegLimit) / _segCount ); - // Estimate eventual total number of segments and files. - _estSegLimit = _segCount + nextSeg; - double filesAfterThisSeg = _fileCount + nextFile; - _estFileLimit = (int)( (filesAfterThisSeg * - _estSegLimit) / _segCount ); + // Write the files. + int[] intParts = { 0,0, 0, 0 }; + // intParts = {size.hi/lo, mod, defl} + Object[] parts = { intParts, null, null, null }; + // parts = { {intParts}, name, data0/1 } + while (getNextFile(parts)) { + //BandStructure.printArrayTo(System.out, intParts, 0, parts.length); + String name = (String) parts[1]; + long size = ( (long)intParts[0] << 32) + + (((long)intParts[1] << 32) >>> 32); - // Write the files. - int[] intParts = { 0,0, 0, 0 }; - // intParts = {size.hi/lo, mod, defl} - Object[] parts = { intParts, null, null, null }; - // parts = { {intParts}, name, data0/1 } - while (getNextFile(parts)) { - //BandStructure.printArrayTo(System.out, intParts, 0, parts.length); - String name = (String) parts[1]; - long size = ( (long)intParts[0] << 32) - + (((long)intParts[1] << 32) >>> 32); - - long mtime = (modtime != Constants.NO_MODTIME ) ? - modtime : intParts[2] ; - boolean deflateHint = (intParts[3] != 0); - ByteBuffer data0 = (ByteBuffer) parts[2]; - ByteBuffer data1 = (ByteBuffer) parts[3]; - writeEntry(jstream, name, mtime, size, deflateHint, - data0, data1); - ++_fileCount; - updateProgress(); - } - long consumed = finish(); - if (_verbose > 0) - Utils.log.info("bytes consumed = "+consumed); - presetInput = getUnusedInput(); - if (presetInput == null && - !Utils.isPackMagic(Utils.readMagic(in))) { - break; - } - if (_verbose > 0 ) { - if (presetInput != null) - Utils.log.info("unused input = "+presetInput); - } - } + long mtime = (modtime != Constants.NO_MODTIME ) ? + modtime : intParts[2] ; + boolean deflateHint = (intParts[3] != 0); + ByteBuffer data0 = (ByteBuffer) parts[2]; + ByteBuffer data1 = (ByteBuffer) parts[3]; + writeEntry(jstream, name, mtime, size, deflateHint, + data0, data1); + ++_fileCount; + updateProgress(); + } + long consumed = finish(); + if (_verbose > 0) + Utils.log.info("bytes consumed = "+consumed); + presetInput = getUnusedInput(); + if (presetInput == null && + !Utils.isPackMagic(Utils.readMagic(in))) { + break; + } + if (_verbose > 0 ) { + if (presetInput != null) + Utils.log.info("unused input = "+presetInput); + } + } } void run(InputStream in, JarOutputStream jstream) throws IOException { - run(in, jstream, null); + run(in, jstream, null); } void run(File inFile, JarOutputStream jstream) throws IOException { - // %%% maybe memory-map the file, and pass it straight into unpacker - ByteBuffer mappedFile = null; - FileInputStream fis = new FileInputStream(inFile); - run(fis, jstream, mappedFile); - fis.close(); - // Note: caller is responsible to finish with jstream. + // %%% maybe memory-map the file, and pass it straight into unpacker + ByteBuffer mappedFile = null; + FileInputStream fis = new FileInputStream(inFile); + run(fis, jstream, mappedFile); + fis.close(); + // Note: caller is responsible to finish with jstream. } + + private void writeEntry(JarOutputStream j, String name, + long mtime, long lsize, boolean deflateHint, + ByteBuffer data0, ByteBuffer data1) throws IOException { + int size = (int)lsize; + if (size != lsize) + throw new IOException("file too large: "+lsize); - private void writeEntry(JarOutputStream j, String name, - long mtime, long lsize, boolean deflateHint, - ByteBuffer data0, ByteBuffer data1) throws IOException { - int size = (int)lsize; - if (size != lsize) - throw new IOException("file too large: "+lsize); + CRC32 crc32 = _crc32; - CRC32 crc32 = _crc32; + if (_verbose > 1) + Utils.log.fine("Writing entry: "+name+" size="+size + +(deflateHint?" deflated":"")); - if (_verbose > 1) - Utils.log.fine("Writing entry: "+name+" size="+size - +(deflateHint?" deflated":"")); + if (_buf.length < size) { + int newSize = size; + while (newSize < _buf.length) { + newSize <<= 1; + if (newSize <= 0) { + newSize = size; + break; + } + } + _buf = new byte[newSize]; + } + assert(_buf.length >= size); - if (_buf.length < size) { - int newSize = size; - while (newSize < _buf.length) { - newSize <<= 1; - if (newSize <= 0) { - newSize = size; - break; - } - } - _buf = new byte[newSize]; - } - assert(_buf.length >= size); + int fillp = 0; + if (data0 != null) { + int size0 = data0.capacity(); + data0.get(_buf, fillp, size0); + fillp += size0; + } + if (data1 != null) { + int size1 = data1.capacity(); + data1.get(_buf, fillp, size1); + fillp += size1; + } + while (fillp < size) { + // Fill in rest of data from the stream itself. + int nr = in.read(_buf, fillp, size - fillp); + if (nr <= 0) throw new IOException("EOF at end of archive"); + fillp += nr; + } - int fillp = 0; - if (data0 != null) { - int size0 = data0.capacity(); - data0.get(_buf, fillp, size0); - fillp += size0; - } - if (data1 != null) { - int size1 = data1.capacity(); - data1.get(_buf, fillp, size1); - fillp += size1; - } - while (fillp < size) { - // Fill in rest of data from the stream itself. - int nr = in.read(_buf, fillp, size - fillp); - if (nr <= 0) throw new IOException("EOF at end of archive"); - fillp += nr; - } + ZipEntry z = new ZipEntry(name); + z.setTime( (long)mtime * 1000); + + if (size == 0) { + z.setMethod(ZipOutputStream.STORED); + z.setSize(0); + z.setCrc(0); + z.setCompressedSize(0); + } else if (!deflateHint) { + z.setMethod(ZipOutputStream.STORED); + z.setSize(size); + z.setCompressedSize(size); + crc32.reset(); + crc32.update(_buf, 0, size); + z.setCrc(crc32.getValue()); + } else { + z.setMethod(Deflater.DEFLATED); + z.setSize(size); + } - ZipEntry z = new ZipEntry(name); - z.setTime( (long)mtime * 1000); + j.putNextEntry(z); - if (size == 0) { - z.setMethod(ZipOutputStream.STORED); - z.setSize(0); - z.setCrc(0); - z.setCompressedSize(0); - } else if (!deflateHint) { - z.setMethod(ZipOutputStream.STORED); - z.setSize(size); - z.setCompressedSize(size); - crc32.reset(); - crc32.update(_buf, 0, size); - z.setCrc(crc32.getValue()); - } else { - z.setMethod(Deflater.DEFLATED); - z.setSize(size); - } + if (size > 0) + j.write(_buf, 0, size); - j.putNextEntry(z); - - if (size > 0) - j.write(_buf, 0, size); - - j.closeEntry(); - if (_verbose > 0) Utils.log.info("Writing " + Utils.zeString(z)); + j.closeEntry(); + if (_verbose > 0) Utils.log.info("Writing " + Utils.zeString(z)); } } + + + 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 --- jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java +++ jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -22,7 +22,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package com.sun.java.util.jar.pack; import java.util.*; @@ -48,9 +47,9 @@ public class PackerImpl implements Pack2 * the packer engines. */ public PackerImpl() { - _props = new PropMap(); - //_props.getProperty() consults defaultProps invisibly. - //_props.putAll(defaultProps); + _props = new PropMap(); + //_props.getProperty() consults defaultProps invisibly. + //_props.putAll(defaultProps); } @@ -62,7 +61,7 @@ public class PackerImpl implements Pack2 * @return A sorted association of option key strings to option values. */ public SortedMap properties() { - return _props; + return _props; } @@ -76,24 +75,24 @@ public class PackerImpl implements Pack2 * @param out an OutputStream * @exception IOException if an error is encountered. */ - public void pack(JarFile in, OutputStream out) throws IOException { - assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : - TimeZone.getDefault(); - try { - Utils.currentInstance.set(this); - if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + public synchronized void pack(JarFile in, OutputStream out) throws IOException { + assert(Utils.currentInstance.get() == null); + TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : + TimeZone.getDefault(); + try { + Utils.currentInstance.set(this); + if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) { - Utils.copyJarFile(in, out); - } else { - (new DoPack()).run(in, out); - in.close(); - } - } finally { - Utils.currentInstance.set(null); - if (tz != null) TimeZone.setDefault(tz); - } + if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) { + Utils.copyJarFile(in, out); + } else { + (new DoPack()).run(in, out); + in.close(); + } + } finally { + Utils.currentInstance.set(null); + if (tz != null) TimeZone.setDefault(tz); + } } /** @@ -110,39 +109,39 @@ public class PackerImpl implements Pack2 * @param out an OutputStream * @exception IOException if an error is encountered. */ - public void pack(JarInputStream in, OutputStream out) throws IOException { - assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : - TimeZone.getDefault(); - try { - Utils.currentInstance.set(this); - if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) { - Utils.copyJarFile(in, out); - } else { - (new DoPack()).run(in, out); - in.close(); - } - } finally { - Utils.currentInstance.set(null); - if (tz != null) TimeZone.setDefault(tz); + public synchronized void pack(JarInputStream in, OutputStream out) throws IOException { + assert(Utils.currentInstance.get() == null); + TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : + TimeZone.getDefault(); + try { + Utils.currentInstance.set(this); + if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) { + Utils.copyJarFile(in, out); + } else { + (new DoPack()).run(in, out); + in.close(); + } + } finally { + Utils.currentInstance.set(null); + if (tz != null) TimeZone.setDefault(tz); - } + } } /** * Register a listener for changes to options. - * @param listener An object to be invoked when a property is changed. + * @param listener An object to be invoked when a property is changed. */ public void addPropertyChangeListener(PropertyChangeListener listener) { - _props.addListener(listener); + _props.addListener(listener); } /** * Remove a listener for the PropertyChange event. - * @param listener The PropertyChange listener to be removed. + * @param listener The PropertyChange listener to be removed. */ public void removePropertyChangeListener(PropertyChangeListener listener) { - _props.removeListener(listener); + _props.removeListener(listener); } @@ -151,471 +150,478 @@ public class PackerImpl implements Pack2 // The packer worker. private class DoPack { - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); - { - _props.setInteger(Pack200.Packer.PROGRESS, 0); - if (verbose > 0) Utils.log.info(_props.toString()); - } + { + _props.setInteger(Pack200.Packer.PROGRESS, 0); + 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: + final Package pkg = new Package(); - final String unknownAttrCommand; - { - String uaMode = _props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); - if (!(Pack200.Packer.STRIP.equals(uaMode) || - Pack200.Packer.PASS.equals(uaMode) || - Pack200.Packer.ERROR.equals(uaMode))) { - throw new RuntimeException("Bad option: " + Pack200.Packer.UNKNOWN_ATTRIBUTE + " = " + uaMode); - } - unknownAttrCommand = uaMode.intern(); - } + final String unknownAttrCommand; + { + String uaMode = _props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); + if (!(Pack200.Packer.STRIP.equals(uaMode) || + Pack200.Packer.PASS.equals(uaMode) || + Pack200.Packer.ERROR.equals(uaMode))) { + throw new RuntimeException("Bad option: " + Pack200.Packer.UNKNOWN_ATTRIBUTE + " = " + uaMode); + } + unknownAttrCommand = uaMode.intern(); + } - final HashMap attrDefs; - final HashMap attrCommands; - { - HashMap attrDefs = new HashMap(); - HashMap attrCommands = new HashMap(); - String[] keys = { - Pack200.Packer.CLASS_ATTRIBUTE_PFX, - Pack200.Packer.FIELD_ATTRIBUTE_PFX, - Pack200.Packer.METHOD_ATTRIBUTE_PFX, - Pack200.Packer.CODE_ATTRIBUTE_PFX - }; - int[] ctypes = { - Constants.ATTR_CONTEXT_CLASS, - Constants.ATTR_CONTEXT_FIELD, - Constants.ATTR_CONTEXT_METHOD, - Constants.ATTR_CONTEXT_CODE - }; - for (int i = 0; i < ctypes.length; i++) { - String pfx = keys[i]; - Map map = _props.prefixMap(pfx); - for (Iterator j = map.keySet().iterator(); j.hasNext(); ) { - String key = (String) j.next(); - assert(key.startsWith(pfx)); - String name = key.substring(pfx.length()); - String layout = _props.getProperty(key); - Object lkey = Attribute.keyForLookup(ctypes[i], name); - if (Pack200.Packer.STRIP.equals(layout) || - Pack200.Packer.PASS.equals(layout) || - Pack200.Packer.ERROR.equals(layout)) { - attrCommands.put(lkey, layout.intern()); - } else { - Attribute.define(attrDefs, ctypes[i], name, layout); - if (verbose > 1) { - Utils.log.fine("Added layout for "+Constants.ATTR_CONTEXT_NAME[i]+" attribute "+name+" = "+layout); - } - assert(attrDefs.containsKey(lkey)); - } - } - } - if (attrDefs.size() > 0) - this.attrDefs = attrDefs; - else - this.attrDefs = null; - if (attrCommands.size() > 0) - this.attrCommands = attrCommands; - else - this.attrCommands = null; - } + final HashMap attrDefs; + final HashMap attrCommands; + { + HashMap attrDefs = new HashMap(); + HashMap attrCommands = new HashMap(); + String[] keys = { + Pack200.Packer.CLASS_ATTRIBUTE_PFX, + Pack200.Packer.FIELD_ATTRIBUTE_PFX, + Pack200.Packer.METHOD_ATTRIBUTE_PFX, + Pack200.Packer.CODE_ATTRIBUTE_PFX + }; + int[] ctypes = { + Constants.ATTR_CONTEXT_CLASS, + Constants.ATTR_CONTEXT_FIELD, + Constants.ATTR_CONTEXT_METHOD, + Constants.ATTR_CONTEXT_CODE + }; + for (int i = 0; i < ctypes.length; i++) { + String pfx = keys[i]; + Map map = _props.prefixMap(pfx); + for (Iterator j = map.keySet().iterator(); j.hasNext(); ) { + String key = (String) j.next(); + assert(key.startsWith(pfx)); + String name = key.substring(pfx.length()); + String layout = _props.getProperty(key); + Object lkey = Attribute.keyForLookup(ctypes[i], name); + if (Pack200.Packer.STRIP.equals(layout) || + Pack200.Packer.PASS.equals(layout) || + Pack200.Packer.ERROR.equals(layout)) { + attrCommands.put(lkey, layout.intern()); + } else { + Attribute.define(attrDefs, ctypes[i], name, layout); + if (verbose > 1) { + Utils.log.fine("Added layout for "+Constants.ATTR_CONTEXT_NAME[i]+" attribute "+name+" = "+layout); + } + assert(attrDefs.containsKey(lkey)); + } + } + } + if (attrDefs.size() > 0) + this.attrDefs = attrDefs; + else + this.attrDefs = null; + if (attrCommands.size() > 0) + this.attrCommands = attrCommands; + else + this.attrCommands = null; + } - final boolean keepFileOrder - = _props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER); - final boolean keepClassOrder - = _props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER); + final boolean keepFileOrder + = _props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER); + final boolean keepClassOrder + = _props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER); - final boolean keepModtime - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME)); - final boolean latestModtime - = Pack200.Packer.LATEST.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME)); - final boolean keepDeflateHint - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.DEFLATE_HINT)); - { - if (!keepModtime && !latestModtime) { - int modtime = _props.getTime(Pack200.Packer.MODIFICATION_TIME); - if (modtime != Constants.NO_MODTIME) { - pkg.default_modtime = modtime; - } - } - if (!keepDeflateHint) { - boolean deflate_hint = _props.getBoolean(Pack200.Packer.DEFLATE_HINT); - if (deflate_hint) { - pkg.default_options |= Constants.AO_DEFLATE_HINT; - } - } - } + final boolean keepModtime + = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME)); + final boolean latestModtime + = Pack200.Packer.LATEST.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME)); + final boolean keepDeflateHint + = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.DEFLATE_HINT)); + { + if (!keepModtime && !latestModtime) { + int modtime = _props.getTime(Pack200.Packer.MODIFICATION_TIME); + if (modtime != Constants.NO_MODTIME) { + pkg.default_modtime = modtime; + } + } + if (!keepDeflateHint) { + boolean deflate_hint = _props.getBoolean(Pack200.Packer.DEFLATE_HINT); + if (deflate_hint) { + pkg.default_options |= Constants.AO_DEFLATE_HINT; + } + } + } - long totalOutputSize = 0; - int segmentCount = 0; - long segmentTotalSize = 0; - long segmentSize = 0; // running counter - final long segmentLimit; - { - long limit; - if (_props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals("")) - limit = -1; - else - limit = _props.getLong(Pack200.Packer.SEGMENT_LIMIT); - limit = Math.min(Integer.MAX_VALUE, limit); - limit = Math.max(-1, limit); - if (limit == -1) - limit = Long.MAX_VALUE; - segmentLimit = limit; - } + long totalOutputSize = 0; + int segmentCount = 0; + long segmentTotalSize = 0; + long segmentSize = 0; // running counter + final long segmentLimit; + { + long limit; + if (_props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals("")) + limit = -1; + else + limit = _props.getLong(Pack200.Packer.SEGMENT_LIMIT); + limit = Math.min(Integer.MAX_VALUE, limit); + limit = Math.max(-1, limit); + if (limit == -1) + limit = Long.MAX_VALUE; + segmentLimit = limit; + } - final List passFiles; // parsed pack.pass.file options - { - // Which class files will be passed through? - passFiles = _props.getProperties(Pack200.Packer.PASS_FILE_PFX); - for (ListIterator i = passFiles.listIterator(); i.hasNext(); ) { - String file = (String) i.next(); - if (file == null) { i.remove(); continue; } - file = Utils.getJarEntryName(file); // normalize '\\' to '/' - if (file.endsWith("/")) - file = file.substring(0, file.length()-1); - i.set(file); - } - if (verbose > 0) Utils.log.info("passFiles = " + passFiles); - } + final List passFiles; // parsed pack.pass.file options + { + // Which class files will be passed through? + passFiles = _props.getProperties(Pack200.Packer.PASS_FILE_PFX); + for (ListIterator i = passFiles.listIterator(); i.hasNext(); ) { + String file = (String) i.next(); + if (file == null) { i.remove(); continue; } + file = Utils.getJarEntryName(file); // normalize '\\' to '/' + if (file.endsWith("/")) + file = file.substring(0, file.length()-1); + i.set(file); + } + 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; - } + { + // 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"); - if (opt != 0) - pkg.default_options |= opt; - } + { + // Hook for testing: Forces use of special archive modes. + int opt = _props.getInteger(Utils.COM_PREFIX+"archive.options"); + if (opt != 0) + pkg.default_options |= opt; + } - // (Done collecting options from _props.) + // (Done collecting options from _props.) - boolean isClassFile(String name) { - if (!name.endsWith(".class")) return false; - for (String prefix = name; ; ) { - if (passFiles.contains(prefix)) return false; - int chop = prefix.lastIndexOf('/'); - if (chop < 0) break; - prefix = prefix.substring(0, chop); - } - return true; - } + boolean isClassFile(String name) { + if (!name.endsWith(".class")) return false; + for (String prefix = name; ; ) { + if (passFiles.contains(prefix)) return false; + int chop = prefix.lastIndexOf('/'); + if (chop < 0) break; + prefix = prefix.substring(0, chop); + } + return true; + } - boolean isMetaInfFile(String name) { - return name.startsWith("/" + Utils.METAINF) || - name.startsWith(Utils.METAINF); - } + boolean isMetaInfFile(String name) { + return name.startsWith("/" + Utils.METAINF) || + name.startsWith(Utils.METAINF); + } - // Get a new package, based on the old one. - private void makeNextPackage() { - pkg.reset(); - } + // Get a new package, based on the old one. + private void makeNextPackage() { + pkg.reset(); + } - class InFile { - final String name; - final JarFile jf; - final JarEntry je; - final File f; - int modtime = Constants.NO_MODTIME; - int options; - InFile(String name) { - this.name = Utils.getJarEntryName(name); - this.f = new File(name); - this.jf = null; - this.je = null; - int timeSecs = getModtime(f.lastModified()); - if (keepModtime && timeSecs != Constants.NO_MODTIME) { - this.modtime = timeSecs; - } else if (latestModtime && timeSecs > pkg.default_modtime) { - pkg.default_modtime = timeSecs; - } - } - InFile(JarFile jf, JarEntry je) { - this.name = Utils.getJarEntryName(je.getName()); - this.f = null; - this.jf = jf; - this.je = je; - int timeSecs = getModtime(je.getTime()); - if (keepModtime && timeSecs != Constants.NO_MODTIME) { - this.modtime = timeSecs; - } else if (latestModtime && timeSecs > pkg.default_modtime) { - pkg.default_modtime = timeSecs; - } - if (keepDeflateHint && je.getMethod() == JarEntry.DEFLATED) { - options |= Constants.FO_DEFLATE_HINT; - } - } - InFile(JarEntry je) { - this(null, je); - } - long getInputLength() { - long len = (je != null)? je.getSize(): f.length(); - assert(len >= 0) : this+".len="+len; - // Bump size by pathname length and modtime/def-hint bytes. - return Math.max(0, len) + name.length() + 5; - } - int getModtime(long timeMillis) { - // Convert milliseconds to seconds. - long seconds = (timeMillis+500) / 1000; - if ((int)seconds == seconds) { - return (int)seconds; - } else { - Utils.log.warning("overflow in modtime for "+f); - return Constants.NO_MODTIME; - } - } - void copyTo(Package.File file) { - if (modtime != Constants.NO_MODTIME) - file.modtime = modtime; - file.options |= options; - } - InputStream getInputStream() throws IOException { - if (jf != null) - return jf.getInputStream(je); - else - return new FileInputStream(f); - } + class InFile { + final String name; + final JarFile jf; + final JarEntry je; + final File f; + int modtime = Constants.NO_MODTIME; + int options; + InFile(String name) { + this.name = Utils.getJarEntryName(name); + this.f = new File(name); + this.jf = null; + this.je = null; + int timeSecs = getModtime(f.lastModified()); + if (keepModtime && timeSecs != Constants.NO_MODTIME) { + this.modtime = timeSecs; + } else if (latestModtime && timeSecs > pkg.default_modtime) { + pkg.default_modtime = timeSecs; + } + } + InFile(JarFile jf, JarEntry je) { + this.name = Utils.getJarEntryName(je.getName()); + this.f = null; + this.jf = jf; + this.je = je; + int timeSecs = getModtime(je.getTime()); + if (keepModtime && timeSecs != Constants.NO_MODTIME) { + this.modtime = timeSecs; + } else if (latestModtime && timeSecs > pkg.default_modtime) { + pkg.default_modtime = timeSecs; + } + if (keepDeflateHint && je.getMethod() == JarEntry.DEFLATED) { + options |= Constants.FO_DEFLATE_HINT; + } + } + InFile(JarEntry je) { + this(null, je); + } + long getInputLength() { + long len = (je != null)? je.getSize(): f.length(); + assert(len >= 0) : this+".len="+len; + // Bump size by pathname length and modtime/def-hint bytes. + return Math.max(0, len) + name.length() + 5; + } + int getModtime(long timeMillis) { + // Convert milliseconds to seconds. + long seconds = (timeMillis+500) / 1000; + if ((int)seconds == seconds) { + return (int)seconds; + } else { + Utils.log.warning("overflow in modtime for "+f); + return Constants.NO_MODTIME; + } + } + void copyTo(Package.File file) { + if (modtime != Constants.NO_MODTIME) + file.modtime = modtime; + file.options |= options; + } + InputStream getInputStream() throws IOException { + if (jf != null) + return jf.getInputStream(je); + else + return new FileInputStream(f); + } - public String toString() { - return name; - } - } + public String toString() { + return name; + } + } - private int nread = 0; // used only if (verbose > 0) - private void noteRead(InFile f) { - nread++; - if (verbose > 2) - Utils.log.fine("...read "+f.name); - if (verbose > 0 && (nread % 1000) == 0) - Utils.log.info("Have read "+nread+" files..."); - } + private int nread = 0; // used only if (verbose > 0) + private void noteRead(InFile f) { + nread++; + if (verbose > 2) + Utils.log.fine("...read "+f.name); + if (verbose > 0 && (nread % 1000) == 0) + Utils.log.info("Have read "+nread+" files..."); + } - void run(JarInputStream in, OutputStream out) throws IOException { - // First thing we do is get the manifest, as JIS does - // not provide the Manifest as an entry. - if (in.getManifest() != null) { - ByteArrayOutputStream tmp = new ByteArrayOutputStream(); - in.getManifest().write(tmp); - InputStream tmpIn = new ByteArrayInputStream(tmp.toByteArray()); - pkg.addFile(readFile(JarFile.MANIFEST_NAME, tmpIn)); - } - for (JarEntry je; (je = in.getNextJarEntry()) != null; ) { - InFile inFile = new InFile(je); + void run(JarInputStream in, OutputStream out) throws IOException { + // First thing we do is get the manifest, as JIS does + // not provide the Manifest as an entry. + if (in.getManifest() != null) { + ByteArrayOutputStream tmp = new ByteArrayOutputStream(); + in.getManifest().write(tmp); + InputStream tmpIn = new ByteArrayInputStream(tmp.toByteArray()); + pkg.addFile(readFile(JarFile.MANIFEST_NAME, tmpIn)); + } + for (JarEntry je; (je = in.getNextJarEntry()) != null; ) { + InFile inFile = new InFile(je); - String name = inFile.name; - Package.File bits = readFile(name, in); - Package.File file = null; - // (5078608) : discount the resource files in META-INF - // from segment computation. - long inflen = (isMetaInfFile(name)) ? 0L : - inFile.getInputLength(); + String name = inFile.name; + Package.File bits = readFile(name, in); + Package.File file = null; + // (5078608) : discount the resource files in META-INF + // from segment computation. + long inflen = (isMetaInfFile(name)) ? 0L : + inFile.getInputLength(); - if ((segmentSize += inflen) > segmentLimit) { - segmentSize -= inflen; - int nextCount = -1; // don't know; it's a stream - flushPartial(out, nextCount); - } - if (verbose > 1) - Utils.log.fine("Reading " + name); + if ((segmentSize += inflen) > segmentLimit) { + segmentSize -= inflen; + int nextCount = -1; // don't know; it's a stream + flushPartial(out, nextCount); + } + if (verbose > 1) + Utils.log.fine("Reading " + name); - assert(je.isDirectory() == name.endsWith("/")); + assert(je.isDirectory() == name.endsWith("/")); - if (isClassFile(name)) { - file = readClass(name, bits.getInputStream()); - } - if (file == null) { - file = bits; - pkg.addFile(file); - } - inFile.copyTo(file); - noteRead(inFile); - } - flushAll(out); - } + if (isClassFile(name)) { + file = readClass(name, bits.getInputStream()); + } + if (file == null) { + file = bits; + pkg.addFile(file); + } + inFile.copyTo(file); + noteRead(inFile); + } + flushAll(out); + } - void run(JarFile in, OutputStream out) throws IOException { - List inFiles = scanJar(in); + void run(JarFile in, OutputStream out) throws IOException { + List inFiles = scanJar(in); - if (verbose > 0) - Utils.log.info("Reading " + inFiles.size() + " files..."); + if (verbose > 0) + Utils.log.info("Reading " + inFiles.size() + " files..."); - int numDone = 0; - for (Iterator i = inFiles.iterator(); i.hasNext(); ) { - InFile inFile = (InFile) i.next(); - String name = inFile.name; - // (5078608) : discount the resource files completely from segmenting - long inflen = (isMetaInfFile(name)) ? 0L : - inFile.getInputLength() ; - if ((segmentSize += inflen) > segmentLimit) { - segmentSize -= inflen; - // Estimate number of remaining segments: - float filesDone = numDone+1; - float segsDone = segmentCount+1; - float filesToDo = inFiles.size() - filesDone; - float segsToDo = filesToDo * (segsDone/filesDone); - if (verbose > 1) - Utils.log.fine("Estimated segments to do: "+segsToDo); - flushPartial(out, (int) Math.ceil(segsToDo)); - } - InputStream strm = inFile.getInputStream(); - if (verbose > 1) - Utils.log.fine("Reading " + name); - Package.File file = null; - if (isClassFile(name)) { - file = readClass(name, strm); - if (file == null) { - strm.close(); - strm = inFile.getInputStream(); - } - } - if (file == null) { - file = readFile(name, strm); - pkg.addFile(file); - } - inFile.copyTo(file); - strm.close(); // tidy up - noteRead(inFile); - numDone += 1; - } - flushAll(out); - } + int numDone = 0; + for (Iterator i = inFiles.iterator(); i.hasNext(); ) { + InFile inFile = (InFile) i.next(); + String name = inFile.name; + // (5078608) : discount the resource files completely from segmenting + long inflen = (isMetaInfFile(name)) ? 0L : + inFile.getInputLength() ; + if ((segmentSize += inflen) > segmentLimit) { + segmentSize -= inflen; + // Estimate number of remaining segments: + float filesDone = numDone+1; + float segsDone = segmentCount+1; + float filesToDo = inFiles.size() - filesDone; + float segsToDo = filesToDo * (segsDone/filesDone); + if (verbose > 1) + Utils.log.fine("Estimated segments to do: "+segsToDo); + flushPartial(out, (int) Math.ceil(segsToDo)); + } + InputStream strm = inFile.getInputStream(); + if (verbose > 1) + Utils.log.fine("Reading " + name); + Package.File file = null; + if (isClassFile(name)) { + file = readClass(name, strm); + if (file == null) { + strm.close(); + strm = inFile.getInputStream(); + } + } + if (file == null) { + file = readFile(name, strm); + pkg.addFile(file); + } + inFile.copyTo(file); + strm.close(); // tidy up + noteRead(inFile); + numDone += 1; + } + flushAll(out); + } - Package.File readClass(String fname, InputStream in) throws IOException { - Package.Class cls = pkg.new Class(fname); - in = new BufferedInputStream(in); - ClassReader reader = new ClassReader(cls, in); - reader.setAttrDefs(attrDefs); - reader.setAttrCommands(attrCommands); - reader.unknownAttrCommand = unknownAttrCommand; - try { - reader.read(); - } catch (Attribute.FormatException ee) { - // He passed up the category to us in layout. - if (ee.layout.equals(Pack200.Packer.PASS)) { - Utils.log.warning("Passing class file uncompressed due to unrecognized attribute: "+fname); - Utils.log.info(ee.toString()); - return null; - } - // Otherwise, it must be an error. - throw ee; - } - pkg.addClass(cls); - return cls.file; - } + Package.File readClass(String fname, InputStream in) throws IOException { + Package.Class cls = pkg.new Class(fname); + in = new BufferedInputStream(in); + ClassReader reader = new ClassReader(cls, in); + reader.setAttrDefs(attrDefs); + reader.setAttrCommands(attrCommands); + reader.unknownAttrCommand = unknownAttrCommand; + try { + reader.read(); + } catch (Attribute.FormatException ee) { + // He passed up the category to us in layout. + if (ee.layout.equals(Pack200.Packer.PASS)) { + Utils.log.warning("Passing class file uncompressed due to unrecognized attribute: "+fname); + Utils.log.info(ee.toString()); + return null; + } + // Otherwise, it must be an error. + throw ee; + } + pkg.addClass(cls); + return cls.file; + } - // Read raw data. - Package.File readFile(String fname, InputStream in) throws IOException { + // Read raw data. + Package.File readFile(String fname, InputStream in) throws IOException { - Package.File file = pkg.new File(fname); - file.readFrom(in); - if (file.isDirectory() && file.getFileLength() != 0) - throw new IllegalArgumentException("Non-empty directory: "+file.getFileName()); - return file; - } + Package.File file = pkg.new File(fname); + file.readFrom(in); + if (file.isDirectory() && file.getFileLength() != 0) + throw new IllegalArgumentException("Non-empty directory: "+file.getFileName()); + return file; + } - void flushPartial(OutputStream out, int nextCount) throws IOException { - if (pkg.files.size() == 0 && pkg.classes.size() == 0) { - return; // do not flush an empty segment - } - flushPackage(out, Math.max(1, nextCount)); - _props.setInteger(Pack200.Packer.PROGRESS, 25); - // In case there will be another segment: - makeNextPackage(); - segmentCount += 1; - segmentTotalSize += segmentSize; - segmentSize = 0; - } + void flushPartial(OutputStream out, int nextCount) throws IOException { + if (pkg.files.size() == 0 && pkg.classes.size() == 0) { + return; // do not flush an empty segment + } + flushPackage(out, Math.max(1, nextCount)); + _props.setInteger(Pack200.Packer.PROGRESS, 25); + // In case there will be another segment: + makeNextPackage(); + segmentCount += 1; + segmentTotalSize += segmentSize; + segmentSize = 0; + } - void flushAll(OutputStream out) throws IOException { - _props.setInteger(Pack200.Packer.PROGRESS, 50); - flushPackage(out, 0); - out.flush(); - _props.setInteger(Pack200.Packer.PROGRESS, 100); - segmentCount += 1; - segmentTotalSize += segmentSize; - segmentSize = 0; - if (verbose > 0 && segmentCount > 1) { - Utils.log.info("Transmitted " - +segmentTotalSize+" input bytes in " - +segmentCount+" segments totaling " - +totalOutputSize+" bytes"); - } - } + void flushAll(OutputStream out) throws IOException { + _props.setInteger(Pack200.Packer.PROGRESS, 50); + flushPackage(out, 0); + out.flush(); + _props.setInteger(Pack200.Packer.PROGRESS, 100); + segmentCount += 1; + segmentTotalSize += segmentSize; + segmentSize = 0; + if (verbose > 0 && segmentCount > 1) { + Utils.log.info("Transmitted " + +segmentTotalSize+" input bytes in " + +segmentCount+" segments totaling " + +totalOutputSize+" bytes"); + } + } - /** Write all information in the current package segment - * to the output stream. - */ - void flushPackage(OutputStream out, int nextCount) throws IOException { - int nfiles = pkg.files.size(); - if (!keepFileOrder) { - // Keeping the order of classes costs about 1% - // Keeping the order of all files costs something more. - if (verbose > 1) Utils.log.fine("Reordering files."); - boolean stripDirectories = true; - pkg.reorderFiles(keepClassOrder, stripDirectories); - } else { - // Package builder must have created a stub for each class. - assert(pkg.files.containsAll(pkg.getClassStubs())); - // Order of stubs in file list must agree with classes. - List res = pkg.files; - assert((res = new ArrayList(pkg.files)) - .retainAll(pkg.getClassStubs()) || true); - assert(res.equals(pkg.getClassStubs())); - } - pkg.trimStubs(); + /** Write all information in the current package segment + * to the output stream. + */ + void flushPackage(OutputStream out, int nextCount) throws IOException { + int nfiles = pkg.files.size(); + if (!keepFileOrder) { + // Keeping the order of classes costs about 1% + // Keeping the order of all files costs something more. + if (verbose > 1) Utils.log.fine("Reordering files."); + boolean stripDirectories = true; + pkg.reorderFiles(keepClassOrder, stripDirectories); + } else { + // Package builder must have created a stub for each class. + assert(pkg.files.containsAll(pkg.getClassStubs())); + // Order of stubs in file list must agree with classes. + List res = pkg.files; + assert((res = new ArrayList(pkg.files)) + .retainAll(pkg.getClassStubs()) || true); + assert(res.equals(pkg.getClassStubs())); + } + pkg.trimStubs(); - // Do some stripping, maybe. - if (_props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses"); + // Do some stripping, maybe. + if (_props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug"); + if (_props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile"); + if (_props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant"); + 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(); + // 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(); - out.flush(); - if (verbose > 0) { - long outSize = pw.archiveSize0+pw.archiveSize1; - totalOutputSize += outSize; - long inSize = segmentSize; - Utils.log.info("Transmitted " - +nfiles+" files of " - +inSize+" input bytes in a segment of " - +outSize+" bytes"); - } - } + PackageWriter pw = new PackageWriter(pkg, out); + pw.archiveNextCount = nextCount; + pw.write(); + out.flush(); + if (verbose > 0) { + long outSize = pw.archiveSize0+pw.archiveSize1; + totalOutputSize += outSize; + long inSize = segmentSize; + Utils.log.info("Transmitted " + +nfiles+" files of " + +inSize+" input bytes in a segment of " + +outSize+" bytes"); + } + } - List scanJar(JarFile jf) throws IOException { - // Collect jar entries, preserving order. - List inFiles = new ArrayList(); - for (Enumeration e = jf.entries(); e.hasMoreElements(); ) { - JarEntry je = (JarEntry) e.nextElement(); - InFile inFile = new InFile(jf, je); - assert(je.isDirectory() == inFile.name.endsWith("/")); - inFiles.add(inFile); - } - return inFiles; - } + List scanJar(JarFile jf) throws IOException { + // Collect jar entries, preserving order. + List inFiles = new ArrayList(); + for (Enumeration e = jf.entries(); e.hasMoreElements(); ) { + JarEntry je = (JarEntry) e.nextElement(); + InFile inFile = new InFile(jf, je); + assert(je.isDirectory() == inFile.name.endsWith("/")); + inFiles.add(inFile); + } + return inFiles; + } } } + + + + + + + diff --git a/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java b/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java --- jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java +++ jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -41,53 +41,53 @@ import java.beans.PropertyChangeEvent; public class UnpackerImpl implements Pack200.Unpacker { - - + + /** * Register a listener for changes to options. * @param listener An object to be invoked when a property is changed. */ public void addPropertyChangeListener(PropertyChangeListener listener) { - _props.addListener(listener); + _props.addListener(listener); } - - + + /** * Remove a listener for the PropertyChange event. * @param listener The PropertyChange listener to be removed. */ public void removePropertyChangeListener(PropertyChangeListener listener) { - _props.removeListener(listener); + _props.removeListener(listener); } - + public UnpackerImpl() { - _props = new PropMap(); - //_props.getProperty() consults defaultProps invisibly. - //_props.putAll(defaultProps); + _props = new PropMap(); + //_props.getProperty() consults defaultProps invisibly. + //_props.putAll(defaultProps); } - + // Private stuff. final PropMap _props; - + /** * Get the set of options for the pack and unpack engines. * @return A sorted association of option key strings to option values. */ public SortedMap properties() { - return _props; + return _props; } - + // Back-pointer to NativeUnpacker, when active. Object _nunp; - - + + public String toString() { - return Utils.getVersionString(); + return Utils.getVersionString(); } - + //Driver routines - + // The unpack worker... /** * Takes a packed-stream InputStream, and writes to a JarOutputStream. Internally @@ -99,36 +99,36 @@ public class UnpackerImpl implements Pac * @param out a JarOutputStream. * @exception IOException if an error is encountered. */ - public void unpack(InputStream in0, JarOutputStream out) throws IOException { - assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : - TimeZone.getDefault(); - - try { - Utils.currentInstance.set(this); - if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); - BufferedInputStream in = new BufferedInputStream(in0); - if (Utils.isJarMagic(Utils.readMagic(in))) { - if (verbose > 0) - Utils.log.info("Copying unpacked JAR file..."); - Utils.copyJarFile(new JarInputStream(in), out); - } else if (_props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) { - (new DoUnpack()).run(in, out); - in.close(); - Utils.markJarFile(out); - } else { - (new NativeUnpack(this)).run(in, out); - in.close(); - Utils.markJarFile(out); - } - } finally { - _nunp = null; - Utils.currentInstance.set(null); - if (tz != null) TimeZone.setDefault(tz); - } + public synchronized void unpack(InputStream in0, JarOutputStream out) throws IOException { + assert(Utils.currentInstance.get() == null); + TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : + TimeZone.getDefault(); + + try { + Utils.currentInstance.set(this); + if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + BufferedInputStream in = new BufferedInputStream(in0); + if (Utils.isJarMagic(Utils.readMagic(in))) { + if (verbose > 0) + Utils.log.info("Copying unpacked JAR file..."); + Utils.copyJarFile(new JarInputStream(in), out); + } else if (_props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) { + (new DoUnpack()).run(in, out); + in.close(); + Utils.markJarFile(out); + } else { + (new NativeUnpack(this)).run(in, out); + in.close(); + Utils.markJarFile(out); + } + } finally { + _nunp = null; + Utils.currentInstance.set(null); + if (tz != null) TimeZone.setDefault(tz); + } } - + /** * Takes an input File containing the pack file, and generates a JarOutputStream. *

@@ -137,121 +137,121 @@ public class UnpackerImpl implements Pac * @param out a JarOutputStream. * @exception IOException if an error is encountered. */ - public void unpack(File in, JarOutputStream out) throws IOException { - // Use the stream-based implementation. - // %%% Reconsider if native unpacker learns to memory-map the file. - FileInputStream instr = new FileInputStream(in); - unpack(instr, out); - if (_props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) { - in.delete(); - } + public synchronized void unpack(File in, JarOutputStream out) throws IOException { + // Use the stream-based implementation. + // %%% Reconsider if native unpacker learns to memory-map the file. + FileInputStream instr = new FileInputStream(in); + unpack(instr, out); + if (_props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) { + in.delete(); + } } - + private class DoUnpack { - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); - - { - _props.setInteger(Pack200.Unpacker.PROGRESS, 0); - } - - // Here's where the bits are read from disk: - final Package pkg = new Package(); - - final boolean keepModtime - = Pack200.Packer.KEEP.equals(_props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP)); - final boolean keepDeflateHint - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP)); - final int modtime; - final boolean deflateHint; - { - if (!keepModtime) { - modtime = _props.getTime(Utils.UNPACK_MODIFICATION_TIME); - } else { - modtime = pkg.default_modtime; - } - - deflateHint = (keepDeflateHint) ? false : - _props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT); - } - - // Checksum apparatus. - final CRC32 crc = new CRC32(); - final ByteArrayOutputStream bufOut = new ByteArrayOutputStream(); - final OutputStream crcOut = new CheckedOutputStream(bufOut, crc); - - public void run(BufferedInputStream in, JarOutputStream out) throws IOException { - if (verbose > 0) { - _props.list(System.out); - } - for (int seg = 1; ; seg++) { - unpackSegment(in, out); - - // Try to get another segment. - if (!Utils.isPackMagic(Utils.readMagic(in))) break; - if (verbose > 0) - Utils.log.info("Finished segment #"+seg); - } - } - - private void unpackSegment(InputStream in, JarOutputStream out) throws IOException { - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0"); - // Process the output directory or jar output. - new PackageReader(pkg, in).read(); - - if (_props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug"); - if (_props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile"); - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50"); - pkg.ensureAllClassFiles(); - // Now write out the files. - HashSet classesToWrite = new HashSet(pkg.getClasses()); - for (Iterator i = pkg.getFiles().iterator(); i.hasNext(); ) { - Package.File file = (Package.File) i.next(); - String name = file.nameString; - JarEntry je = new JarEntry(Utils.getJarEntryName(name)); - boolean deflate; - - deflate = (keepDeflateHint) ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) || - ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) : - deflateHint; - - boolean needCRC = !deflate; // STORE mode requires CRC - - if (needCRC) crc.reset(); - bufOut.reset(); - if (file.isClassStub()) { - Package.Class cls = file.getStubClass(); - assert(cls != null); - new ClassWriter(cls, needCRC ? crcOut : bufOut).write(); - classesToWrite.remove(cls); // for an error check - } else { - // collect data & maybe CRC - file.writeTo(needCRC ? crcOut : bufOut); - } - je.setMethod(deflate ? JarEntry.DEFLATED : JarEntry.STORED); - if (needCRC) { - if (verbose > 0) - Utils.log.info("stored size="+bufOut.size()+" and crc="+crc.getValue()); - - je.setMethod(JarEntry.STORED); - je.setSize(bufOut.size()); - je.setCrc(crc.getValue()); - } - if (keepModtime) { - je.setTime(file.modtime); - // Convert back to milliseconds - je.setTime((long)file.modtime * 1000); - } else { - je.setTime((long)modtime * 1000); - } - out.putNextEntry(je); - bufOut.writeTo(out); - out.closeEntry(); - if (verbose > 0) - Utils.log.info("Writing "+Utils.zeString((ZipEntry)je)); - } - assert(classesToWrite.isEmpty()); - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100"); - pkg.reset(); // reset for the next segment, if any - } + final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + + { + _props.setInteger(Pack200.Unpacker.PROGRESS, 0); + } + + // Here's where the bits are read from disk: + final Package pkg = new Package(); + + final boolean keepModtime + = Pack200.Packer.KEEP.equals(_props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP)); + final boolean keepDeflateHint + = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP)); + final int modtime; + final boolean deflateHint; + { + if (!keepModtime) { + modtime = _props.getTime(Utils.UNPACK_MODIFICATION_TIME); + } else { + modtime = pkg.default_modtime; + } + + deflateHint = (keepDeflateHint) ? false : + _props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT); + } + + // Checksum apparatus. + final CRC32 crc = new CRC32(); + final ByteArrayOutputStream bufOut = new ByteArrayOutputStream(); + final OutputStream crcOut = new CheckedOutputStream(bufOut, crc); + + public void run(BufferedInputStream in, JarOutputStream out) throws IOException { + if (verbose > 0) { + _props.list(System.out); + } + for (int seg = 1; ; seg++) { + unpackSegment(in, out); + + // Try to get another segment. + if (!Utils.isPackMagic(Utils.readMagic(in))) break; + if (verbose > 0) + Utils.log.info("Finished segment #"+seg); + } + } + + private void unpackSegment(InputStream in, JarOutputStream out) throws IOException { + _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0"); + // Process the output directory or jar output. + new PackageReader(pkg, in).read(); + + if (_props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug"); + if (_props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile"); + _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50"); + pkg.ensureAllClassFiles(); + // Now write out the files. + HashSet classesToWrite = new HashSet(pkg.getClasses()); + for (Iterator i = pkg.getFiles().iterator(); i.hasNext(); ) { + Package.File file = (Package.File) i.next(); + String name = file.nameString; + JarEntry je = new JarEntry(Utils.getJarEntryName(name)); + boolean deflate; + + deflate = (keepDeflateHint) ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) || + ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) : + deflateHint; + + boolean needCRC = !deflate; // STORE mode requires CRC + + if (needCRC) crc.reset(); + bufOut.reset(); + if (file.isClassStub()) { + Package.Class cls = file.getStubClass(); + assert(cls != null); + new ClassWriter(cls, needCRC ? crcOut : bufOut).write(); + classesToWrite.remove(cls); // for an error check + } else { + // collect data & maybe CRC + file.writeTo(needCRC ? crcOut : bufOut); + } + je.setMethod(deflate ? JarEntry.DEFLATED : JarEntry.STORED); + if (needCRC) { + if (verbose > 0) + Utils.log.info("stored size="+bufOut.size()+" and crc="+crc.getValue()); + + je.setMethod(JarEntry.STORED); + je.setSize(bufOut.size()); + je.setCrc(crc.getValue()); + } + if (keepModtime) { + je.setTime(file.modtime); + // Convert back to milliseconds + je.setTime((long)file.modtime * 1000); + } else { + je.setTime((long)modtime * 1000); + } + out.putNextEntry(je); + bufOut.writeTo(out); + out.closeEntry(); + if (verbose > 0) + Utils.log.info("Writing "+Utils.zeString((ZipEntry)je)); + } + assert(classesToWrite.isEmpty()); + _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100"); + pkg.reset(); // reset for the next segment, if any + } } } diff --git a/src/share/native/com/sun/java/util/jar/pack/bands.cpp b/src/share/native/com/sun/java/util/jar/pack/bands.cpp --- jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp +++ jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -81,11 +81,11 @@ void band::readData(int expectedLength) assert(defc->B() > 1 && defc->L() > 0); // must have already read from previous band: assert(bn >= BAND_LIMIT || bn <= 0 - || bn == e_cp_Utf8_big_chars - || endsWith(name, "_lo") // preceded by _hi conditional band - || bn == e_file_options // preceded by conditional band - || u->rp == u->all_bands[bn-1].maxRP() - || u->all_bands[bn-1].defc == null); + || bn == e_cp_Utf8_big_chars + || endsWith(name, "_lo") // preceded by _hi conditional band + || bn == e_file_options // preceded by conditional band + || u->rp == u->all_bands[bn-1].maxRP() + || u->all_bands[bn-1].defc == null); value_stream xvs; coding* valc = defc; @@ -136,7 +136,7 @@ void band::readData(int expectedLength) #ifndef PRODUCT printcr(3,"readFrom %s at %p [%d values, %d bytes, cp=%d/%d]", - (name?name:"(band)"), minRP(), length, size(), cp1, cp2); + (name?name:"(band)"), minRP(), length, size(), cp1, cp2); if (u->verbose_bands || u->verbose >= 4) dump(); if (ix != null && u->verbose != 0 && length > 0) { @@ -187,10 +187,14 @@ void band::setIndexByTag(byte tag) { entry* band::getRefCommon(cpindex* ix_, bool nullOKwithCaller) { CHECK_0; + if (ix_ == NULL) { + abort("no index"); + return NULL; + } assert(ix_->ixTag == ixTag - || (ixTag == CONSTANT_Literal - && ix_->ixTag >= CONSTANT_Integer - && ix_->ixTag <= CONSTANT_String)); + || (ixTag == CONSTANT_Literal + && ix_->ixTag >= CONSTANT_Integer + && ix_->ixTag <= CONSTANT_String)); int n = vs[0].getInt() - nullOK; // Note: band-local nullOK means null encodes as 0. // But nullOKwithCaller means caller is willing to tolerate a null. @@ -245,9 +249,9 @@ int band::getIntCount(int tag) { hist0 = U_NEW(int, (HIST0_MAX - HIST0_MIN)+1); CHECK_0; for (int k = length; k > 0; k--) { - int x = vs[0].getInt(); - if (x >= HIST0_MIN && x <= HIST0_MAX) - hist0[x - HIST0_MIN] += 1; + int x = vs[0].getInt(); + if (x >= HIST0_MIN && x <= HIST0_MAX) + hist0[x - HIST0_MIN] += 1; } rewind(); } @@ -262,7 +266,7 @@ int band::getIntCount(int tag) { } #define INDEX_INIT(tag, nullOK, subindex) \ - ((tag) + (subindex)*SUBINDEX_BIT + (nullOK)*256) + ((tag) + (subindex)*SUBINDEX_BIT + (nullOK)*256) #define INDEX(tag) INDEX_INIT(tag, 0, 0) #define NULL_OR_INDEX(tag) INDEX_INIT(tag, 1, 0) @@ -437,13 +441,13 @@ const band_init all_band_inits[] = { {0} }; #define NUM_BAND_INITS \ - (sizeof(all_band_inits)/sizeof(all_band_inits[0])) + (sizeof(all_band_inits)/sizeof(all_band_inits[0])) band* band::makeBands(unpacker* u) { band* all_bands = U_NEW(band, BAND_LIMIT); for (int i = 0; i < BAND_LIMIT; i++) { assert((byte*)&all_band_inits[i+1] - < (byte*)all_band_inits+sizeof(all_band_inits)); + < (byte*)all_band_inits+sizeof(all_band_inits)); const band_init& bi = all_band_inits[i]; band& b = all_bands[i]; coding* defc = coding::findBySpec(bi.defc); @@ -472,3 +476,5 @@ void band::initIndexes(unpacker* u) { } } } + + diff --git a/src/share/native/com/sun/java/util/jar/pack/bands.h b/src/share/native/com/sun/java/util/jar/pack/bands.h --- jdk/src/share/native/com/sun/java/util/jar/pack/bands.h +++ jdk/src/share/native/com/sun/java/util/jar/pack/bands.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - + // -*- C++ -*- struct entry; struct cpindex; @@ -50,7 +50,7 @@ struct band { // properties for attribute layout elements: byte le_kind; // EK_XXX - byte le_bci; // 0,EK_BCI,EK_BCD,EK_BCO + byte le_bci; // 0,EK_BCI,EK_BCD,EK_BCO byte le_back; // ==EF_BACK byte le_len; // 0,1,2,4 (size in classfile), or call addr band** le_body; // body of repl, union, call (null-terminated) @@ -101,8 +101,8 @@ struct band { int getByte() { assert(ix == null); return vs[0].getByte(); } int getInt() { assert(ix == null); return vs[0].getInt(); } - entry* getRefN() { assert(ix != null); return getRefCommon(ix, true); } - entry* getRef() { assert(ix != null); return getRefCommon(ix, false); } + entry* getRefN() { return getRefCommon(ix, true); } + entry* getRef() { return getRefCommon(ix, false); } entry* getRefUsing(cpindex* ix2) { assert(ix == null); return getRefCommon(ix2, true); } entry* getRefCommon(cpindex* ix, bool nullOK); diff --git a/src/share/native/com/sun/java/util/jar/pack/defines.h b/src/share/native/com/sun/java/util/jar/pack/defines.h --- jdk/src/share/native/com/sun/java/util/jar/pack/defines.h +++ jdk/src/share/native/com/sun/java/util/jar/pack/defines.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -22,10 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - + // random definitions -#ifdef _MSC_VER +#ifdef _MSC_VER #include #include #else @@ -94,15 +94,15 @@ typedef unsigned int uLong; // Historica #else typedef unsigned long uLong; #endif -#ifdef _MSC_VER -typedef LONGLONG jlong; -typedef DWORDLONG julong; -#define MKDIR(dir) mkdir(dir) -#define getpid() _getpid() -#define PATH_MAX MAX_PATH -#define dup2(a,b) _dup2(a,b) +#ifdef _MSC_VER +typedef LONGLONG jlong; +typedef DWORDLONG julong; +#define MKDIR(dir) mkdir(dir) +#define getpid() _getpid() +#define PATH_MAX MAX_PATH +#define dup2(a,b) _dup2(a,b) #define strcasecmp(s1, s2) _stricmp(s1,s2) -#define tempname _tempname +#define tempname _tempname #define sleep Sleep #else typedef signed char byte; @@ -123,37 +123,40 @@ enum { false, true }; #define null (0) -#ifndef __sparc +#ifndef __sparc #define intptr_t jlong #endif #define ptrlowbits(x) ((int) (intptr_t)(x)) +/* Back and forth from jlong to pointer */ +#define ptr2jlong(x) ((jlong)(size_t)(void*)(x)) +#define jlong2ptr(x) ((void*)(size_t)(x)) // Keys used by Java: -#define UNPACK_DEFLATE_HINT "unpack.deflate.hint" +#define UNPACK_DEFLATE_HINT "unpack.deflate.hint" -#define COM_PREFIX "com.sun.java.util.jar.pack." -#define UNPACK_MODIFICATION_TIME COM_PREFIX"unpack.modification.time" -#define DEBUG_VERBOSE COM_PREFIX"verbose" +#define COM_PREFIX "com.sun.java.util.jar.pack." +#define UNPACK_MODIFICATION_TIME COM_PREFIX"unpack.modification.time" +#define DEBUG_VERBOSE COM_PREFIX"verbose" -#define ZIP_ARCHIVE_MARKER_COMMENT "PACK200" +#define ZIP_ARCHIVE_MARKER_COMMENT "PACK200" // The following are not known to the Java classes: -#define UNPACK_LOG_FILE COM_PREFIX"unpack.log.file" -#define UNPACK_REMOVE_PACKFILE COM_PREFIX"unpack.remove.packfile" +#define UNPACK_LOG_FILE COM_PREFIX"unpack.log.file" +#define UNPACK_REMOVE_PACKFILE COM_PREFIX"unpack.remove.packfile" // Called from unpacker layers -#define _CHECK_DO(t,x) { if (t) {x;} } +#define _CHECK_DO(t,x) { if (t) {x;} } -#define CHECK _CHECK_DO(aborting(), return) -#define CHECK_(y) _CHECK_DO(aborting(), return y) -#define CHECK_0 _CHECK_DO(aborting(), return 0) +#define CHECK _CHECK_DO(aborting(), return) +#define CHECK_(y) _CHECK_DO(aborting(), return y) +#define CHECK_0 _CHECK_DO(aborting(), return 0) -#define CHECK_NULL(p) _CHECK_DO((p)==null, return) -#define CHECK_NULL_(y,p) _CHECK_DO((p)==null, return y) -#define CHECK_NULL_0(p) _CHECK_DO((p)==null, return 0) +#define CHECK_NULL(p) _CHECK_DO((p)==null, return) +#define CHECK_NULL_(y,p) _CHECK_DO((p)==null, return y) +#define CHECK_NULL_0(p) _CHECK_DO((p)==null, return 0) #define CHECK_COUNT(t) if (t < 0){abort("bad value count");} CHECK diff --git a/src/share/native/com/sun/java/util/jar/pack/jni.cpp b/src/share/native/com/sun/java/util/jar/pack/jni.cpp --- jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp +++ jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -43,6 +43,9 @@ #include "bands.h" #include "constants.h" #include "zip.h" + +#include "jni_util.h" + #include "unpack.h" @@ -50,17 +53,19 @@ static jmethodID currentInstMID; static jmethodID currentInstMID; static jmethodID readInputMID; static jclass NIclazz; +static jmethodID getUnpackerPtrMID; static char* dbg = null; #define THROW_IOE(x) JNU_ThrowIOException(env,x) static jlong read_input_via_jni(unpacker* self, - void* buf, jlong minlen, jlong maxlen); - + void* buf, jlong minlen, jlong maxlen); + static unpacker* get_unpacker(JNIEnv *env, jobject pObj, bool noCreate=false) { - unpacker* uPtr = (unpacker*) env->GetLongField(pObj, unpackerPtrFID); - //fprintf(stderr, "get_unpacker(%p) uPtr=%p\n", pObj, uPtr); + unpacker* uPtr; + jlong p = env->CallLongMethod(pObj, getUnpackerPtrMID); + uPtr = (unpacker*)jlong2ptr(p); if (uPtr == null) { if (noCreate) return null; uPtr = new unpacker(); @@ -89,11 +94,15 @@ static unpacker* get_unpacker() { if (env == null) return null; jobject pObj = env->CallStaticObjectMethod(NIclazz, currentInstMID); - //fprintf(stderr, "get_unpacker() pObj=%p\n", pObj); - if (pObj == null) - return null; - // Got pObj and env; now do it the easy way. - return get_unpacker(env, pObj); + //fprintf(stderr, "get_unpacker0() pObj=%p\n", pObj); + if (pObj != null) { + // Got pObj and env; now do it the easy way. + return get_unpacker(env, pObj); + } + // this should really not happen, if it does something is seriously + // wrong throw an exception + THROW_IOE(ERROR_INTERNAL); + return null; } static void free_unpacker(JNIEnv *env, jobject pObj, unpacker* uPtr) { @@ -113,36 +122,47 @@ unpacker* unpacker::current() { // Callback for fetching data, Java style. Calls NativeUnpack.readInputFn(). static jlong read_input_via_jni(unpacker* self, - void* buf, jlong minlen, jlong maxlen) { + void* buf, jlong minlen, jlong maxlen) { JNIEnv* env = (JNIEnv*) self->jnienv; jobject pbuf = env->NewDirectByteBuffer(buf, maxlen); return env->CallLongMethod((jobject) self->jniobj, readInputMID, - pbuf, minlen); + pbuf, minlen); } -JNIEXPORT void JNICALL +JNIEXPORT void JNICALL Java_com_sun_java_util_jar_pack_NativeUnpack_initIDs(JNIEnv *env, jclass clazz) { +#ifndef PRODUCT dbg = getenv("DEBUG_ATTACH"); while( dbg != null) { sleep(10); } +#endif NIclazz = (jclass) env->NewGlobalRef(clazz); unpackerPtrFID = env->GetFieldID(clazz, "unpackerPtr", "J"); currentInstMID = env->GetStaticMethodID(clazz, "currentInstance", - "()Ljava/lang/Object;"); + "()Ljava/lang/Object;"); readInputMID = env->GetMethodID(clazz, "readInputFn", - "(Ljava/nio/ByteBuffer;J)J"); + "(Ljava/nio/ByteBuffer;J)J"); + + getUnpackerPtrMID = env->GetMethodID(clazz, "getUnpackerPtr", "()J"); + if (unpackerPtrFID == null || currentInstMID == null || readInputMID == null || - NIclazz == null) { + NIclazz == null || + getUnpackerPtrMID == null) { THROW_IOE("cannot init class members"); } } -JNIEXPORT jlong JNICALL +JNIEXPORT jlong JNICALL Java_com_sun_java_util_jar_pack_NativeUnpack_start(JNIEnv *env, jobject pObj, - jobject pBuf, jlong offset) { - unpacker* uPtr = get_unpacker(env, pObj); - + jobject pBuf, jlong offset) { + // try to get the unpacker pointer the hard way first, we do this to ensure + // valid object pointers and env is intact, if not now is good time to bail. + unpacker* uPtr = get_unpacker(); + //fprintf(stderr, "start(%p) uPtr=%p initializing\n", pObj, uPtr); + if (uPtr == null) { + return -1; + } // redirect our io to the default log file or whatever. uPtr->redirect_stdio(); @@ -158,6 +178,13 @@ Java_com_sun_java_util_jar_pack_NativeUn else { buf = (char*)buf + (size_t)offset; buflen -= (size_t)offset; } } + + // before we start off we make sure there is no other error by the time we + // get here + if (uPtr->aborting()) { + THROW_IOE(uPtr->get_abort_message()); + return 0; + } uPtr->start(buf, buflen); if (uPtr->aborting()) { @@ -166,13 +193,13 @@ Java_com_sun_java_util_jar_pack_NativeUn } return ((jlong) - uPtr->get_segments_remaining() << 32) + uPtr->get_segments_remaining() << 32) + uPtr->get_files_remaining(); } -JNIEXPORT jboolean JNICALL -Java_com_sun_java_util_jar_pack_NativeUnpack_getNextFile(JNIEnv *env, jobject pObj, - jobjectArray pParts) { +JNIEXPORT jboolean JNICALL +Java_com_sun_java_util_jar_pack_NativeUnpack_getNextFile(JNIEnv *env, jobject pObj, + jobjectArray pParts) { unpacker* uPtr = get_unpacker(env, pObj); unpacker::file* filep = uPtr->get_next_file(); @@ -201,19 +228,19 @@ Java_com_sun_java_util_jar_pack_NativeUn jobject pDataBuf = null; if (filep->data[0].len > 0) pDataBuf = env->NewDirectByteBuffer(filep->data[0].ptr, - filep->data[0].len); + filep->data[0].len); env->SetObjectArrayElement(pParts, pidx++, pDataBuf); pDataBuf = null; if (filep->data[1].len > 0) pDataBuf = env->NewDirectByteBuffer(filep->data[1].ptr, - filep->data[1].len); + filep->data[1].len); env->SetObjectArrayElement(pParts, pidx++, pDataBuf); return true; } -JNIEXPORT jobject JNICALL +JNIEXPORT jobject JNICALL Java_com_sun_java_util_jar_pack_NativeUnpack_getUnusedInput(JNIEnv *env, jobject pObj) { unpacker* uPtr = get_unpacker(env, pObj); unpacker::file* filep = &uPtr->cur_file; @@ -225,14 +252,18 @@ Java_com_sun_java_util_jar_pack_NativeUn // We have fetched all the files. // Now swallow up any remaining input. - if (uPtr->input_remaining() == 0) + if (uPtr->input_remaining() == 0) { return null; - else - return env->NewDirectByteBuffer(uPtr->input_scan(), - uPtr->input_remaining()); + } + else { + bytes remaining_bytes; + remaining_bytes.malloc(uPtr->input_remaining()); + remaining_bytes.copyFrom(uPtr->input_scan(), uPtr->input_remaining()); + return env->NewDirectByteBuffer(remaining_bytes.ptr, remaining_bytes.len); + } } -JNIEXPORT jlong JNICALL +JNIEXPORT jlong JNICALL Java_com_sun_java_util_jar_pack_NativeUnpack_finish(JNIEnv *env, jobject pObj) { unpacker* uPtr = get_unpacker(env, pObj, false); if (uPtr == null) return 0; @@ -241,9 +272,9 @@ Java_com_sun_java_util_jar_pack_NativeUn return consumed; } -JNIEXPORT jboolean JNICALL -Java_com_sun_java_util_jar_pack_NativeUnpack_setOption(JNIEnv *env, jobject pObj, - jstring pProp, jstring pValue) { +JNIEXPORT jboolean JNICALL +Java_com_sun_java_util_jar_pack_NativeUnpack_setOption(JNIEnv *env, jobject pObj, + jstring pProp, jstring pValue) { unpacker* uPtr = get_unpacker(env, pObj); const char* prop = env->GetStringUTFChars(pProp, JNI_FALSE); const char* value = env->GetStringUTFChars(pValue, JNI_FALSE); @@ -253,9 +284,9 @@ Java_com_sun_java_util_jar_pack_NativeUn return retval; } -JNIEXPORT jstring JNICALL -Java_com_sun_java_util_jar_pack_NativeUnpack_getOption(JNIEnv *env, jobject pObj, - jstring pProp) { +JNIEXPORT jstring JNICALL +Java_com_sun_java_util_jar_pack_NativeUnpack_getOption(JNIEnv *env, jobject pObj, + jstring pProp) { unpacker* uPtr = get_unpacker(env, pObj); const char* prop = env->GetStringUTFChars(pProp, JNI_FALSE); diff --git a/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/src/share/native/com/sun/java/util/jar/pack/unpack.cpp --- jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -38,7 +38,7 @@ #include - + #include "defines.h" #include "bytes.h" @@ -185,9 +185,9 @@ struct entry { || (tag2 == CONSTANT_Utf8 && tag == CONSTANT_Signature) #ifndef PRODUCT || (tag2 == CONSTANT_Literal - && tag >= CONSTANT_Integer && tag <= CONSTANT_String && tag != CONSTANT_Class) + && tag >= CONSTANT_Integer && tag <= CONSTANT_String && tag != CONSTANT_Class) || (tag2 == CONSTANT_Member - && tag >= CONSTANT_Fieldref && tag <= CONSTANT_InterfaceMethodref) + && tag >= CONSTANT_Fieldref && tag <= CONSTANT_InterfaceMethodref) #endif ; } @@ -238,9 +238,9 @@ int entry::typeSize() { // else fall through case 'L': sigp = strchr(sigp, ';'); - if (sigp == null) { - unpack_abort("bad data"); - return 0; + if (sigp == null) { + unpack_abort("bad data"); + return 0; } sigp += 1; break; @@ -252,11 +252,13 @@ int entry::typeSize() { } inline cpindex* cpool::getFieldIndex(entry* classRef) { + if (classRef == NULL) { abort("missing class reference"); return NULL; } assert(classRef->tagMatches(CONSTANT_Class)); assert((uint)classRef->inord < tag_count[CONSTANT_Class]); return &member_indexes[classRef->inord*2+0]; } inline cpindex* cpool::getMethodIndex(entry* classRef) { + if (classRef == NULL) { abort("missing class reference"); return NULL; } assert(classRef->tagMatches(CONSTANT_Class)); assert((uint)classRef->inord < tag_count[CONSTANT_Class]); return &member_indexes[classRef->inord*2+1]; @@ -512,11 +514,10 @@ void unpacker::read_file_header() { AH_CP_NUMBER_LEN = 4, // int/float/long/double AH_SPECIAL_FORMAT_LEN = 2, // layouts/band-headers AH_LENGTH_MIN = AH_LENGTH - -(AH_FILE_HEADER_LEN+AH_SPECIAL_FORMAT_LEN+AH_CP_NUMBER_LEN), - ARCHIVE_SIZE_MIN = AH_LENGTH_MIN - (AH_LENGTH_0 + AH_ARCHIVE_SIZE_LEN), + -(AH_FILE_HEADER_LEN+AH_SPECIAL_FORMAT_LEN+AH_CP_NUMBER_LEN), + ARCHIVE_SIZE_MIN = AH_LENGTH_MIN - (AH_LENGTH_0 + AH_ARCHIVE_SIZE_LEN), FIRST_READ = MAGIC_BYTES + AH_LENGTH_MIN }; - assert(AH_LENGTH_MIN == 15); // # of UNSIGNED5 fields required after archive_magic assert(ARCHIVE_SIZE_MIN == 10); // # of UNSIGNED5 fields required after archive_size @@ -580,15 +581,15 @@ void unpacker::read_file_header() { for (;;) { jarout->write_data(rp, input_remaining()); if (foreign_buf) - break; // one-time use of a passed in buffer + break; // one-time use of a passed in buffer if (input.size() < CHUNK) { - // Get some breathing room. - input.set(U_NEW(byte, (size_t) CHUNK + C_SLOP), (size_t) CHUNK); - CHECK; + // Get some breathing room. + input.set(U_NEW(byte, (size_t) CHUNK + C_SLOP), (size_t) CHUNK); + CHECK; } rp = rplimit = input.base(); if (!ensure_input(1)) - break; + break; } jarout->closeJarFile(false); #endif @@ -612,16 +613,16 @@ void unpacker::read_file_header() { hdrVals += 2; if (magic != JAVA_PACKAGE_MAGIC || - (majver != JAVA5_PACKAGE_MAJOR_VERSION && - majver != JAVA6_PACKAGE_MAJOR_VERSION) || - (minver != JAVA5_PACKAGE_MINOR_VERSION && + (majver != JAVA5_PACKAGE_MAJOR_VERSION && + majver != JAVA6_PACKAGE_MAJOR_VERSION) || + (minver != JAVA5_PACKAGE_MINOR_VERSION && minver != JAVA6_PACKAGE_MINOR_VERSION)) { char message[200]; sprintf(message, "@" ERROR_FORMAT ": magic/ver = " - "%08X/%d.%d should be %08X/%d.%d OR %08X/%d.%d\n", - magic, majver, minver, - JAVA_PACKAGE_MAGIC, JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION, - JAVA_PACKAGE_MAGIC, JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION); + "%08X/%d.%d should be %08X/%d.%d OR %08X/%d.%d\n", + magic, majver, minver, + JAVA_PACKAGE_MAGIC, JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION, + JAVA_PACKAGE_MAGIC, JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION); abort(message); } CHECK; @@ -635,7 +636,7 @@ void unpacker::read_file_header() { #undef ORBIT if ((archive_options & ~OPTION_LIMIT) != 0) { fprintf(errstrm, "Warning: Illegal archive options 0x%x\n", - archive_options); + archive_options); abort("illegal archive options"); return; } @@ -675,7 +676,7 @@ void unpacker::read_file_header() { if (archive_size < header_size_1) { abort("too much read-ahead"); // somehow we pre-fetched too much? return; - } + } input.set(U_NEW(byte, add_size(header_size_0, archive_size, C_SLOP)), (size_t) header_size_0 + archive_size); CHECK; @@ -756,9 +757,9 @@ void unpacker::read_file_header() { case CONSTANT_Float: case CONSTANT_Long: case CONSTANT_Double: - cp_counts[k] = 0; - hdrValsSkipped += 1; - continue; + cp_counts[k] = 0; + hdrValsSkipped += 1; + continue; } } cp_counts[k] = hdr.getInt(); @@ -813,7 +814,7 @@ void unpacker::read_file_header() { bytes band_headers; // The "1+" allows an initial byte to be pushed on the front. band_headers.set(1+U_NEW(byte, 1+band_headers_size+C_SLOP), - band_headers_size); + band_headers_size); CHECK; // Start scanning band headers here: band_headers.copyFrom(rp, band_headers.len); @@ -874,7 +875,7 @@ void cpool::init(unpacker* u_, int count IMPLICIT_ENTRY_COUNT = 1 // empty Utf8 string }; if (len >= (1<<29) || len < 0 - || next_entry >= CP_SIZE_LIMIT+IMPLICIT_ENTRY_COUNT) { + || next_entry >= CP_SIZE_LIMIT+IMPLICIT_ENTRY_COUNT) { abort("archive too large: constant pool limit exceeded"); return; } @@ -935,9 +936,9 @@ static byte* skip_Utf8_chars(byte* cp, i int ch = *cp & 0xFF; if ((ch & 0xC0) != 0x80) { if (len-- == 0) - return cp; + return cp; if (ch < 0x80 && len == 0) - return cp+1; + return cp+1; } } } @@ -963,9 +964,9 @@ static int compare_Utf8_chars(bytes& b1, if (c1 == 0xC0 && (p1[i+1] & 0xFF) == 0x80) c1 = 0; if (c2 == 0xC0 && (p2[i+1] & 0xFF) == 0x80) c2 = 0; if (c0 == 0xC0) { - assert(((c1|c2) & 0xC0) == 0x80); // c1 & c2 are extension chars - if (c1 == 0x80) c1 = 0; // will sort below c2 - if (c2 == 0x80) c2 = 0; // will sort below c1 + assert(((c1|c2) & 0xC0) == 0x80); // c1 & c2 are extension chars + if (c1 == 0x80) c1 = 0; // will sort below c2 + if (c2 == 0x80) c2 = 0; // will sort below c1 } return c1 - c2; } @@ -1024,9 +1025,9 @@ void unpacker::read_Utf8_values(entry* c chars.malloc(size3); } else { if (!charbuf.canAppend(size3+1)) { - assert(charbuf.allocated == 0 || tmallocs.contains(charbuf.base())); - charbuf.init(CHUNK); // Reset to new buffer. - tmallocs.add(charbuf.base()); + assert(charbuf.allocated == 0 || tmallocs.contains(charbuf.base())); + charbuf.init(CHUNK); // Reset to new buffer. + tmallocs.add(charbuf.base()); } chars.set(charbuf.grow(size3+1), size3); } @@ -1191,9 +1192,9 @@ void unpacker::read_single_refs(band& cp // Maintain cross-reference: entry* &htref = cp.hashTabRef(indexTag, e.value.b); if (htref == null) { - // Note that if two identical classes are transmitted, - // the first is taken to be the canonical one. - htref = &e; + // Note that if two identical classes are transmitted, + // the first is taken to be the canonical one. + htref = &e; } } } @@ -1202,7 +1203,7 @@ void unpacker::read_single_refs(band& cp maybe_inline void unpacker::read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag, - entry* cpMap, int len) { + entry* cpMap, int len) { band& cp_band1 = cp_band; band& cp_band2 = cp_band.nextBand(); cp_band1.setIndexByTag(ref1Tag); @@ -1214,6 +1215,7 @@ void unpacker::read_double_refs(band& cp entry& e = cpMap[i]; e.refs = U_NEW(entry*, e.nrefs = 2); e.refs[0] = cp_band1.getRef(); + CHECK; e.refs[1] = cp_band2.getRef(); CHECK; } @@ -1302,23 +1304,23 @@ void unpacker::read_cp() { break; case CONSTANT_NameandType: read_double_refs(cp_Descr_name /*& cp_Descr_type*/, - CONSTANT_Utf8, CONSTANT_Signature, - cpMap, len); + CONSTANT_Utf8, CONSTANT_Signature, + cpMap, len); break; case CONSTANT_Fieldref: read_double_refs(cp_Field_class /*& cp_Field_desc*/, - CONSTANT_Class, CONSTANT_NameandType, - cpMap, len); + CONSTANT_Class, CONSTANT_NameandType, + cpMap, len); break; case CONSTANT_Methodref: read_double_refs(cp_Method_class /*& cp_Method_desc*/, - CONSTANT_Class, CONSTANT_NameandType, - cpMap, len); + CONSTANT_Class, CONSTANT_NameandType, + cpMap, len); break; case CONSTANT_InterfaceMethodref: read_double_refs(cp_Imethod_class /*& cp_Imethod_desc*/, - CONSTANT_Class, CONSTANT_NameandType, - cpMap, len); + CONSTANT_Class, CONSTANT_NameandType, + cpMap, len); break; default: assert(false); @@ -1384,8 +1386,8 @@ inline inline unpacker::layout_definition* unpacker::attr_definitions::defineLayout(int idx, - entry* nameEntry, - const char* layout) { + entry* nameEntry, + const char* layout) { const char* name = nameEntry->value.b.strval(); layout_definition* lo = defineLayout(idx, name, layout); CHECK_0; @@ -1395,8 +1397,8 @@ unpacker::attr_definitions::defineLayout unpacker::layout_definition* unpacker::attr_definitions::defineLayout(int idx, - const char* name, - const char* layout) { + const char* name, + const char* layout) { assert(flag_limit != 0); // must be set up already if (idx >= 0) { // Fixed attr. @@ -1419,12 +1421,12 @@ unpacker::attr_definitions::defineLayout } CHECK_0; layouts.get(idx) = lo; - return lo; + return lo; } band** unpacker::attr_definitions::buildBands(unpacker::layout_definition* lo) { - int i; + int i; if (lo->elems != null) return lo->bands(); if (lo->layout[0] == '\0') { @@ -1448,11 +1450,11 @@ unpacker::attr_definitions::buildBands(u int num_callables = 0; if (hasCallables) { while (bands[num_callables] != null) { - if (bands[num_callables]->le_kind != EK_CBLE) { - abort("garbage mixed with callables"); - break; - } - num_callables += 1; + if (bands[num_callables]->le_kind != EK_CBLE) { + abort("garbage mixed with callables"); + break; + } + num_callables += 1; } } for (i = 0; i < calls_to_link.length(); i++) { @@ -1461,8 +1463,8 @@ unpacker::attr_definitions::buildBands(u // Determine the callee. int call_num = call.le_len; if (call_num < 0 || call_num >= num_callables) { - abort("bad call in layout"); - break; + abort("bad call in layout"); + break; } band& cble = *bands[call_num]; // Link the call to it. @@ -1540,7 +1542,7 @@ unpacker::attr_definitions::buildBands(u const char* unpacker::attr_definitions::parseIntLayout(const char* lp, band* &res, - byte le_kind, bool can_be_signed) { + byte le_kind, bool can_be_signed) { const char* lp0 = lp; band* b = U_NEW(band, 1); CHECK_(lp); @@ -1619,7 +1621,7 @@ unpacker::attr_definitions::popBody(int const char* unpacker::attr_definitions::parseLayout(const char* lp, band** &res, - int curCble) { + int curCble) { const char* lp0 = lp; int bs_base = band_stack.length(); bool top_level = (bs_base == 0); @@ -1636,18 +1638,18 @@ unpacker::attr_definitions::parseLayout( break; case 'P': { - int le_bci = EK_BCI; - if (*lp == 'O') { - ++lp; - le_bci = EK_BCID; - } - assert(*lp != 'S'); // no PSH, etc. - lp = parseIntLayout(lp, b, EK_INT); - b->le_bci = le_bci; - if (le_bci == EK_BCI) - b->defc = coding::findBySpec(BCI5_spec); - else - b->defc = coding::findBySpec(BRANCH5_spec); + int le_bci = EK_BCI; + if (*lp == 'O') { + ++lp; + le_bci = EK_BCID; + } + assert(*lp != 'S'); // no PSH, etc. + lp = parseIntLayout(lp, b, EK_INT); + b->le_bci = le_bci; + if (le_bci == EK_BCI) + b->defc = coding::findBySpec(BCI5_spec); + else + b->defc = coding::findBySpec(BRANCH5_spec); } break; case 'O': @@ -1665,25 +1667,25 @@ unpacker::attr_definitions::parseLayout( case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']' lp = parseIntLayout(lp, b, EK_UN, can_be_signed); { - int union_base = band_stack.length(); - for (;;) { // for each case - band& k_case = *U_NEW(band, 1); - CHECK_(lp); - band_stack.add(&k_case); - k_case.le_kind = EK_CASE; - k_case.bn = bands_made++; - if (*lp++ != '(') { - abort("bad union case"); - return ""; - } - if (*lp++ != ')') { - --lp; // reparse - // Read some case values. (Use band_stack for temp. storage.) - int case_base = band_stack.length(); - for (;;) { - int caseval = 0; - lp = parseNumeral(lp, caseval); - band_stack.add((void*)caseval); + int union_base = band_stack.length(); + for (;;) { // for each case + band& k_case = *U_NEW(band, 1); + CHECK_(lp); + band_stack.add(&k_case); + k_case.le_kind = EK_CASE; + k_case.bn = bands_made++; + if (*lp++ != '(') { + abort("bad union case"); + return ""; + } + if (*lp++ != ')') { + --lp; // reparse + // Read some case values. (Use band_stack for temp. storage.) + int case_base = band_stack.length(); + for (;;) { + int caseval = 0; + lp = parseNumeral(lp, caseval); + band_stack.add((void*)caseval); if (*lp == '-') { // new in version 160, allow (1-5) for (1,2,3,4,5) if (u->majver < JAVA6_PACKAGE_MAJOR_VERSION) { @@ -1706,111 +1708,111 @@ unpacker::attr_definitions::parseLayout( if (caseval == caselimit) break; } } - if (*lp != ',') break; - lp++; - } - if (*lp++ != ')') { - abort("bad case label"); - return ""; - } - // save away the case labels - int ntags = band_stack.length() - case_base; - int* tags = U_NEW(int, add_size(ntags, 1)); - CHECK_(lp); - k_case.le_casetags = tags; - *tags++ = ntags; - for (int i = 0; i < ntags; i++) { - *tags++ = ptrlowbits(band_stack.get(case_base+i)); - } - band_stack.popTo(case_base); - CHECK_(lp); - } - // Got le_casetags. Now grab the body. - assert(*lp == '['); - ++lp; - lp = parseLayout(lp, k_case.le_body, curCble); - CHECK_(lp); - if (k_case.le_casetags == null) break; // done - } - b->le_body = popBody(union_base); + if (*lp != ',') break; + lp++; + } + if (*lp++ != ')') { + abort("bad case label"); + return ""; + } + // save away the case labels + int ntags = band_stack.length() - case_base; + int* tags = U_NEW(int, add_size(ntags, 1)); + CHECK_(lp); + k_case.le_casetags = tags; + *tags++ = ntags; + for (int i = 0; i < ntags; i++) { + *tags++ = ptrlowbits(band_stack.get(case_base+i)); + } + band_stack.popTo(case_base); + CHECK_(lp); + } + // Got le_casetags. Now grab the body. + assert(*lp == '['); + ++lp; + lp = parseLayout(lp, k_case.le_body, curCble); + CHECK_(lp); + if (k_case.le_casetags == null) break; // done + } + b->le_body = popBody(union_base); } break; case '(': // call: '(' -?NN* ')' { - band& call = *U_NEW(band, 1); - CHECK_(lp); - band_stack.add(&call); - call.le_kind = EK_CALL; - call.bn = bands_made++; - call.le_body = U_NEW(band*, 2); // fill in later - int call_num = 0; - lp = parseNumeral(lp, call_num); - call.le_back = (call_num <= 0); - call_num += curCble; // numeral is self-relative offset - call.le_len = call_num; //use le_len as scratch - calls_to_link.add(&call); - CHECK_(lp); - if (*lp++ != ')') { - abort("bad call label"); - return ""; + band& call = *U_NEW(band, 1); + CHECK_(lp); + band_stack.add(&call); + call.le_kind = EK_CALL; + call.bn = bands_made++; + call.le_body = U_NEW(band*, 2); // fill in later + int call_num = 0; + lp = parseNumeral(lp, call_num); + call.le_back = (call_num <= 0); + call_num += curCble; // numeral is self-relative offset + call.le_len = call_num; //use le_len as scratch + calls_to_link.add(&call); + CHECK_(lp); + if (*lp++ != ')') { + abort("bad call label"); + return ""; } } break; case 'K': // reference_type: constant_ref case 'R': // reference_type: schema_ref { - int ixTag = CONSTANT_None; - if (lp[-1] == 'K') { - switch (*lp++) { - case 'I': ixTag = CONSTANT_Integer; break; - case 'J': ixTag = CONSTANT_Long; break; - case 'F': ixTag = CONSTANT_Float; break; - case 'D': ixTag = CONSTANT_Double; break; - case 'S': ixTag = CONSTANT_String; break; - case 'Q': ixTag = CONSTANT_Literal; break; - } - } else { - switch (*lp++) { - case 'C': ixTag = CONSTANT_Class; break; - case 'S': ixTag = CONSTANT_Signature; break; - case 'D': ixTag = CONSTANT_NameandType; break; - case 'F': ixTag = CONSTANT_Fieldref; break; - case 'M': ixTag = CONSTANT_Methodref; break; - case 'I': ixTag = CONSTANT_InterfaceMethodref; break; - case 'U': ixTag = CONSTANT_Utf8; break; //utf8_ref - case 'Q': ixTag = CONSTANT_All; break; //untyped_ref - } - } - if (ixTag == CONSTANT_None) { - abort("bad reference layout"); - break; - } - bool nullOK = false; - if (*lp == 'N') { - nullOK = true; - lp++; - } - lp = parseIntLayout(lp, b, EK_REF); - b->defc = coding::findBySpec(UNSIGNED5_spec); - b->initRef(ixTag, nullOK); + int ixTag = CONSTANT_None; + if (lp[-1] == 'K') { + switch (*lp++) { + case 'I': ixTag = CONSTANT_Integer; break; + case 'J': ixTag = CONSTANT_Long; break; + case 'F': ixTag = CONSTANT_Float; break; + case 'D': ixTag = CONSTANT_Double; break; + case 'S': ixTag = CONSTANT_String; break; + case 'Q': ixTag = CONSTANT_Literal; break; + } + } else { + switch (*lp++) { + case 'C': ixTag = CONSTANT_Class; break; + case 'S': ixTag = CONSTANT_Signature; break; + case 'D': ixTag = CONSTANT_NameandType; break; + case 'F': ixTag = CONSTANT_Fieldref; break; + case 'M': ixTag = CONSTANT_Methodref; break; + case 'I': ixTag = CONSTANT_InterfaceMethodref; break; + case 'U': ixTag = CONSTANT_Utf8; break; //utf8_ref + case 'Q': ixTag = CONSTANT_All; break; //untyped_ref + } + } + if (ixTag == CONSTANT_None) { + abort("bad reference layout"); + break; + } + bool nullOK = false; + if (*lp == 'N') { + nullOK = true; + lp++; + } + lp = parseIntLayout(lp, b, EK_REF); + b->defc = coding::findBySpec(UNSIGNED5_spec); + b->initRef(ixTag, nullOK); } break; case '[': { - // [callable1][callable2]... - if (!top_level) { - abort("bad nested callable"); - break; - } - curCble += 1; - NOT_PRODUCT(int call_num = band_stack.length() - bs_base); - band& cble = *U_NEW(band, 1); - CHECK_(lp); - band_stack.add(&cble); - cble.le_kind = EK_CBLE; - NOT_PRODUCT(cble.le_len = call_num); - cble.bn = bands_made++; - lp = parseLayout(lp, cble.le_body, curCble); + // [callable1][callable2]... + if (!top_level) { + abort("bad nested callable"); + break; + } + curCble += 1; + NOT_PRODUCT(int call_num = band_stack.length() - bs_base); + band& cble = *U_NEW(band, 1); + CHECK_(lp); + band_stack.add(&cble); + cble.le_kind = EK_CBLE; + NOT_PRODUCT(cble.le_len = call_num); + cble.bn = bands_made++; + lp = parseLayout(lp, cble.le_body, curCble); } break; case ']': @@ -1880,10 +1882,10 @@ void unpacker::read_attr_defs() { "(115)[RUH]" "(91)[NH[(0)]]" "(64)[" - // nested annotation: - "RSH" - "NH[RUH(0)]" - "]" + // nested annotation: + "RSH" + "NH[RUH(0)]" + "]" "()[]" "]" ); @@ -1897,16 +1899,16 @@ void unpacker::read_attr_defs() { for (i = 0; i < ATTR_CONTEXT_LIMIT; i++) { attr_definitions& ad = attr_defs[i]; ad.defineLayout(X_ATTR_RuntimeVisibleAnnotations, - "RuntimeVisibleAnnotations", md_layout_A); + "RuntimeVisibleAnnotations", md_layout_A); ad.defineLayout(X_ATTR_RuntimeInvisibleAnnotations, - "RuntimeInvisibleAnnotations", md_layout_A); + "RuntimeInvisibleAnnotations", md_layout_A); if (i != ATTR_CONTEXT_METHOD) continue; ad.defineLayout(METHOD_ATTR_RuntimeVisibleParameterAnnotations, - "RuntimeVisibleParameterAnnotations", md_layout_P); + "RuntimeVisibleParameterAnnotations", md_layout_P); ad.defineLayout(METHOD_ATTR_RuntimeInvisibleParameterAnnotations, - "RuntimeInvisibleParameterAnnotations", md_layout_P); + "RuntimeInvisibleParameterAnnotations", md_layout_P); ad.defineLayout(METHOD_ATTR_AnnotationDefault, - "AnnotationDefault", md_layout_V); + "AnnotationDefault", md_layout_V); } attr_definition_headers.readData(attr_definition_count); @@ -1939,6 +1941,7 @@ void unpacker::read_attr_defs() { int attrc = ADH_BYTE_CONTEXT(header); int idx = ADH_BYTE_INDEX(header); entry* name = attr_definition_name.getRef(); + CHECK; entry* layout = attr_definition_layout.getRef(); CHECK; attr_defs[attrc].defineLayout(idx, name, layout->value.b.strval()); @@ -2043,7 +2046,9 @@ void unpacker::read_ics() { if (ics[i].name == NO_ENTRY_YET) { // Long form. ics[i].outer = ic_outer_class.getRefN(); + CHECK; ics[i].name = ic_name.getRefN(); + CHECK; } else { // Fill in outer and name based on inner. bytes& n = ics[i].inner->value.b; @@ -2058,48 +2063,48 @@ void unpacker::read_ics() { int pkglen = lastIndexOf(SLASH_MIN, SLASH_MAX, n, nlen) + 1; dollar2 = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, nlen); if (dollar2 < 0) { - abort(); - return; + abort(); + return; } assert(dollar2 >= pkglen); if (isDigitString(n, dollar2+1, nlen)) { - // n = (/)*$ - number = n.slice(dollar2+1, nlen); - name.set(null,0); - dollar1 = dollar2; + // n = (/)*$ + number = n.slice(dollar2+1, nlen); + name.set(null,0); + dollar1 = dollar2; } else if (pkglen < (dollar1 - = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, dollar2-1)) - && isDigitString(n, dollar1+1, dollar2)) { - // n = (/)*$$ - number = n.slice(dollar1+1, dollar2); - name = n.slice(dollar2+1, nlen); + = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, dollar2-1)) + && isDigitString(n, dollar1+1, dollar2)) { + // n = (/)*$$ + number = n.slice(dollar1+1, dollar2); + name = n.slice(dollar2+1, nlen); } else { - // n = (/)*$ - dollar1 = dollar2; - number.set(null,0); - name = n.slice(dollar2+1, nlen); + // n = (/)*$ + dollar1 = dollar2; + number.set(null,0); + name = n.slice(dollar2+1, nlen); } if (number.ptr == null) - pkgOuter = n.slice(0, dollar1); + pkgOuter = n.slice(0, dollar1); else - pkgOuter.set(null,0); + pkgOuter.set(null,0); printcr(5,"=> %s$ 0%s $%s", - pkgOuter.string(), number.string(), name.string()); + pkgOuter.string(), number.string(), name.string()); if (pkgOuter.ptr != null) - ics[i].outer = cp.ensureClass(pkgOuter); + ics[i].outer = cp.ensureClass(pkgOuter); if (name.ptr != null) - ics[i].name = cp.ensureUtf8(name); + ics[i].name = cp.ensureUtf8(name); } // update child/sibling list if (ics[i].outer != null) { uint outord = ics[i].outer->inord; if (outord != NO_INORD) { - assert(outord < cp.tag_count[CONSTANT_Class]); - ics[i].next_sibling = ic_child_index[outord]; - ic_child_index[outord] = &ics[i]; + assert(outord < cp.tag_count[CONSTANT_Class]); + ics[i].next_sibling = ic_child_index[outord]; + ic_child_index[outord] = &ics[i]; } } } @@ -2149,7 +2154,7 @@ void unpacker::read_classes() { read_code_headers(); printcr(1,"scanned %d classes, %d fields, %d methods, %d code headers", - class_count, field_count, method_count, code_count); + class_count, field_count, method_count, code_count); } maybe_inline @@ -2226,11 +2231,11 @@ void unpacker::read_attrs(int attrc, int band** bands = ad.buildBands(lo); CHECK; if (lo->hasCallables()) { - for (i = 0; bands[i] != null; i++) { - if (bands[i]->le_back) { - assert(bands[i]->le_kind == EK_CBLE); - backwardCounts += 1; - } + for (i = 0; bands[i] != null; i++) { + if (bands[i]->le_back) { + assert(bands[i]->le_kind == EK_CBLE); + backwardCounts += 1; + } } } } @@ -2427,7 +2432,7 @@ void unpacker::attr_definitions::readBan layout_definition* lo = getLayout(idx); if (lo != null) { printcr(1, "counted %d [redefined = %d predefined = %d] attributes of type %s.%s", - count, isRedefined(idx), isPredefined(idx), + count, isRedefined(idx), isPredefined(idx), ATTR_CONTEXT_NAME[attrc], lo->name); } bool hasCallables = lo->hasCallables(); @@ -2444,10 +2449,10 @@ void unpacker::attr_definitions::readBan band& j_cble = *bands[j]; assert(j_cble.le_kind == EK_CBLE); if (j_cble.le_back) { - // Add in the predicted effects of backward calls, too. - int back_calls = xxx_attr_calls().getInt(); - j_cble.expectMoreLength(back_calls); - // In a moment, more forward calls may increment j_cble.length. + // Add in the predicted effects of backward calls, too. + int back_calls = xxx_attr_calls().getInt(); + j_cble.expectMoreLength(back_calls); + // In a moment, more forward calls may increment j_cble.length. } } // Now consult whichever callables have non-zero entry counts. @@ -2467,38 +2472,38 @@ void unpacker::attr_definitions::readBan switch (b.le_kind) { case EK_REPL: { - int reps = b.getIntTotal(); - readBandData(b.le_body, reps); + int reps = b.getIntTotal(); + readBandData(b.le_body, reps); } break; case EK_UN: { - int remaining = count; - for (k = 0; b.le_body[k] != null; k++) { - band& k_case = *b.le_body[k]; - int k_count = 0; - if (k_case.le_casetags == null) { - k_count = remaining; // last (empty) case - } else { - int* tags = k_case.le_casetags; - int ntags = *tags++; // 1st element is length (why not?) - while (ntags-- > 0) { - int tag = *tags++; - k_count += b.getIntCount(tag); - } - } - readBandData(k_case.le_body, k_count); - remaining -= k_count; - } - assert(remaining == 0); + int remaining = count; + for (k = 0; b.le_body[k] != null; k++) { + band& k_case = *b.le_body[k]; + int k_count = 0; + if (k_case.le_casetags == null) { + k_count = remaining; // last (empty) case + } else { + int* tags = k_case.le_casetags; + int ntags = *tags++; // 1st element is length (why not?) + while (ntags-- > 0) { + int tag = *tags++; + k_count += b.getIntCount(tag); + } + } + readBandData(k_case.le_body, k_count); + remaining -= k_count; + } + assert(remaining == 0); } break; case EK_CALL: // Push the count forward, if it is not a backward call. if (!b.le_back) { - band& cble = *b.le_body[0]; - assert(cble.le_kind == EK_CBLE); - cble.expectMoreLength(count); + band& cble = *b.le_body[0]; + assert(cble.le_kind == EK_CBLE); + cble.expectMoreLength(count); } break; case EK_CBLE: @@ -2522,12 +2527,12 @@ band** findMatchingCase(int matchTag, ba int* tags = k_case.le_casetags; int ntags = *tags++; // 1st element is length for (; ntags > 0; ntags--) { - int tag = *tags++; - if (tag == matchTag) - break; + int tag = *tags++; + if (tag == matchTag) + break; } if (ntags == 0) - continue; // does not match + continue; // does not match } return k_case.le_body; } @@ -2549,46 +2554,47 @@ void unpacker::putlayout(band** body) { if (b.defc != null) { // It has data, so unparse an element. if (b.ixTag != CONSTANT_None) { - assert(le_kind == EK_REF); - if (b.ixTag == CONSTANT_Literal) - e = b.getRefUsing(cp.getKQIndex()); - else - e = b.getRefN(); - switch (b.le_len) { - case 0: break; - case 1: putu1ref(e); break; - case 2: putref(e); break; - case 4: putu2(0); putref(e); break; - default: assert(false); - } + assert(le_kind == EK_REF); + if (b.ixTag == CONSTANT_Literal) + e = b.getRefUsing(cp.getKQIndex()); + else + e = b.getRefN(); + CHECK; + switch (b.le_len) { + case 0: break; + case 1: putu1ref(e); break; + case 2: putref(e); break; + case 4: putu2(0); putref(e); break; + default: assert(false); + } } else { - assert(le_kind == EK_INT || le_kind == EK_REPL || le_kind == EK_UN); - x = b.getInt(); - - assert(!b.le_bci || prevBCI == to_bci(prevBII)); - switch (b.le_bci) { - case EK_BCI: // PH: transmit R(bci), store bci - x = to_bci(prevBII = x); - prevBCI = x; - break; - case EK_BCID: // POH: transmit D(R(bci)), store bci - x = to_bci(prevBII += x); - prevBCI = x; - break; - case EK_BCO: // OH: transmit D(R(bci)), store D(bci) - x = to_bci(prevBII += x) - prevBCI; - prevBCI += x; - break; - } - assert(!b.le_bci || prevBCI == to_bci(prevBII)); - - switch (b.le_len) { - case 0: break; - case 1: putu1(x); break; - case 2: putu2(x); break; - case 4: putu4(x); break; - default: assert(false); - } + assert(le_kind == EK_INT || le_kind == EK_REPL || le_kind == EK_UN); + x = b.getInt(); + + assert(!b.le_bci || prevBCI == to_bci(prevBII)); + switch (b.le_bci) { + case EK_BCI: // PH: transmit R(bci), store bci + x = to_bci(prevBII = x); + prevBCI = x; + break; + case EK_BCID: // POH: transmit D(R(bci)), store bci + x = to_bci(prevBII += x); + prevBCI = x; + break; + case EK_BCO: // OH: transmit D(R(bci)), store D(bci) + x = to_bci(prevBII += x) - prevBCI; + prevBCI += x; + break; + } + assert(!b.le_bci || prevBCI == to_bci(prevBII)); + + switch (b.le_len) { + case 0: break; + case 1: putu1(x); break; + case 2: putu2(x); break; + case 4: putu4(x); break; + default: assert(false); + } } } @@ -2597,7 +2603,7 @@ void unpacker::putlayout(band** body) { case EK_REPL: // x is the repeat count while (x-- > 0) { - putlayout(b.le_body); + putlayout(b.le_body); } break; case EK_UN: @@ -2606,10 +2612,10 @@ void unpacker::putlayout(band** body) { break; case EK_CALL: { - band& cble = *b.le_body[0]; - assert(cble.le_kind == EK_CBLE); - assert(cble.le_len == b.le_len); - putlayout(cble.le_body); + band& cble = *b.le_body[0]; + assert(cble.le_kind == EK_CBLE); + assert(cble.le_len == b.le_len); + putlayout(cble.le_body); } break; @@ -2635,7 +2641,7 @@ void unpacker::read_files() { // FO_IS_CLASS_STUB might be set, causing overlap between classes and files for (int i = 0; i < file_count; i++) { if ((file_options.getInt() & FO_IS_CLASS_STUB) != 0) { - allFiles -= 1; // this one counts as both class and file + allFiles -= 1; // this one counts as both class and file } } file_options.rewind(); @@ -2646,9 +2652,9 @@ void unpacker::read_files() { maybe_inline void unpacker::get_code_header(int& max_stack, - int& max_na_locals, - int& handler_count, - int& cflags) { + int& max_na_locals, + int& handler_count, + int& cflags) { int sc = code_headers.getByte(); if (sc == 0) { max_stack = max_na_locals = handler_count = cflags = -1; @@ -2801,7 +2807,7 @@ inline // called exactly once => inline inline // called exactly once => inline void unpacker::read_bcs() { printcr(3, "reading compressed bytecodes and operands for %d codes...", - code_count); + code_count); // read from bc_codes and bc_case_count fillbytes all_switch_ops; @@ -2822,80 +2828,80 @@ void unpacker::read_bcs() { // Scan one method: for (;;) { if (opptr+2 > oplimit) { - rp = opptr; - ensure_input(2); - oplimit = rplimit; - rp = rp0; // back up + rp = opptr; + ensure_input(2); + oplimit = rplimit; + rp = rp0; // back up } if (opptr == oplimit) { abort(); break; } int bc = *opptr++ & 0xFF; bool isWide = false; if (bc == bc_wide) { - if (opptr == oplimit) { abort(); break; } - bc = *opptr++ & 0xFF; - isWide = true; + if (opptr == oplimit) { abort(); break; } + bc = *opptr++ & 0xFF; + isWide = true; } // Adjust expectations of various band sizes. switch (bc) { case bc_tableswitch: case bc_lookupswitch: - all_switch_ops.addByte(bc); - break; + all_switch_ops.addByte(bc); + break; case bc_iinc: - bc_local.expectMoreLength(1); - bc_which = isWide ? &bc_short : &bc_byte; - bc_which->expectMoreLength(1); - break; + bc_local.expectMoreLength(1); + bc_which = isWide ? &bc_short : &bc_byte; + bc_which->expectMoreLength(1); + break; case bc_sipush: - bc_short.expectMoreLength(1); - break; + bc_short.expectMoreLength(1); + break; case bc_bipush: - bc_byte.expectMoreLength(1); - break; + bc_byte.expectMoreLength(1); + break; case bc_newarray: - bc_byte.expectMoreLength(1); - break; + bc_byte.expectMoreLength(1); + break; case bc_multianewarray: - assert(ref_band_for_op(bc) == &bc_classref); - bc_classref.expectMoreLength(1); - bc_byte.expectMoreLength(1); - break; + assert(ref_band_for_op(bc) == &bc_classref); + bc_classref.expectMoreLength(1); + bc_byte.expectMoreLength(1); + break; case bc_ref_escape: - bc_escrefsize.expectMoreLength(1); - bc_escref.expectMoreLength(1); - break; + bc_escrefsize.expectMoreLength(1); + bc_escref.expectMoreLength(1); + break; case bc_byte_escape: - bc_escsize.expectMoreLength(1); - // bc_escbyte will have to be counted too - break; + bc_escsize.expectMoreLength(1); + // bc_escbyte will have to be counted too + break; default: - if (is_invoke_init_op(bc)) { - bc_initref.expectMoreLength(1); - break; - } - bc_which = ref_band_for_self_op(bc, isAload, junkBC); - if (bc_which != null) { - bc_which->expectMoreLength(1); - break; - } - if (is_branch_op(bc)) { - bc_label.expectMoreLength(1); - break; - } - bc_which = ref_band_for_op(bc); - if (bc_which != null) { - bc_which->expectMoreLength(1); - assert(bc != bc_multianewarray); // handled elsewhere - break; - } - if (is_local_slot_op(bc)) { - bc_local.expectMoreLength(1); - break; - } - break; + if (is_invoke_init_op(bc)) { + bc_initref.expectMoreLength(1); + break; + } + bc_which = ref_band_for_self_op(bc, isAload, junkBC); + if (bc_which != null) { + bc_which->expectMoreLength(1); + break; + } + if (is_branch_op(bc)) { + bc_label.expectMoreLength(1); + break; + } + bc_which = ref_band_for_op(bc); + if (bc_which != null) { + bc_which->expectMoreLength(1); + assert(bc != bc_multianewarray); // handled elsewhere + break; + } + if (is_local_slot_op(bc)) { + bc_local.expectMoreLength(1); + break; + } + break; case bc_end_marker: - // Increment k and test against code_count. - goto doneScanningMethod; + // Increment k and test against code_count. + goto doneScanningMethod; } } doneScanningMethod:{} @@ -2929,15 +2935,15 @@ void unpacker::read_bcs() { bc_escbyte.readData(bc_escsize.getIntTotal()); printcr(3, "scanned %d opcode and %d operand bytes for %d codes...", - (int)(bc_codes.size()), - (int)(bc_escsize.maxRP() - bc_case_value.minRP()), - code_count); + (int)(bc_codes.size()), + (int)(bc_escsize.maxRP() - bc_case_value.minRP()), + code_count); } void unpacker::read_bands() { byte* rp0 = rp; int i; - + CHECK; read_file_header(); CHECK; @@ -3063,8 +3069,8 @@ void cpool::expandSignatures() { int c = form.ptr[j]; buf.addByte(c); if (c == 'L') { - entry* cls = e.refs[refnum++]; - buf.append(cls->className()->asUtf8()); + entry* cls = e.refs[refnum++]; + buf.append(cls->className()->asUtf8()); } } assert(refnum == e.nrefs); @@ -3099,7 +3105,7 @@ void cpool::expandSignatures() { for (int j = 0; j < e.nrefs; j++) { entry*& e2 = e.refs[j]; if (e2 != null && e2->tag == CONSTANT_Signature) - e2 = e2->refs[0]; + e2 = e2->refs[0]; } } } @@ -3141,14 +3147,14 @@ void cpool::initMemberIndexes() { int fc = field_counts[i]; int mc = method_counts[i]; all_indexes[i*2+0].init(fc, field_ix+fbase, - CONSTANT_Fieldref + SUBINDEX_BIT); + CONSTANT_Fieldref + SUBINDEX_BIT); all_indexes[i*2+1].init(mc, method_ix+mbase, - CONSTANT_Methodref + SUBINDEX_BIT); + CONSTANT_Methodref + SUBINDEX_BIT); // reuse field_counts and member_counts as fill pointers: field_counts[i] = fbase; method_counts[i] = mbase; printcr(3, "class %d fields @%d[%d] methods @%d[%d]", - i, fbase, fc, mbase, mc); + i, fbase, fc, mbase, mc); fbase += fc+1; mbase += mc+1; // (the +1 leaves a space between every subarray) @@ -3178,7 +3184,7 @@ void cpool::initMemberIndexes() { cpindex* fix = getFieldIndex(cls); cpindex* mix = getMethodIndex(cls); printcr(2, "field and method index for %s [%d] [%d]", - cls->string(), mix->len, fix->len); + cls->string(), mix->len, fix->len); prevord = -1; for (j = 0, len = fix->len; j < len; j++) { entry* f = fix->get(j); @@ -3204,7 +3210,7 @@ void cpool::initMemberIndexes() { } assert(fvisited == nfields); assert(mvisited == nmethods); -#endif +#endif // Free intermediate buffers. u->free_temps(); @@ -3438,8 +3444,8 @@ bool unpacker::set_option(const char* pr bool unpacker::set_option(const char* prop, const char* value) { if (prop == NULL) return false; if (strcmp(prop, UNPACK_DEFLATE_HINT) == 0) { - deflate_hint_or_zero = ( (value == null || strcmp(value, "keep") == 0) - ? 0: BOOL_TF(value) ? +1: -1); + deflate_hint_or_zero = ( (value == null || strcmp(value, "keep") == 0) + ? 0: BOOL_TF(value) ? +1: -1); #ifdef HAVE_STRIP } else if (strcmp(prop, UNPACK_STRIP_COMPILE) == 0) { strip_compile = STR_TF(value); @@ -3466,7 +3472,7 @@ bool unpacker::set_option(const char* pr } else { modification_time_or_zero = atoi(value); if (modification_time_or_zero == 0) - modification_time_or_zero = 1; // make non-zero + modification_time_or_zero = 1; // make non-zero } } else if (strcmp(prop, UNPACK_LOG_FILE) == 0) { log_file = (value == null)? value: saveStr(value); @@ -3597,14 +3603,16 @@ void unpacker::dump_options() { // Usage: unpack a byte buffer -// packptr is a reference to byte buffer containing a +// packptr is a reference to byte buffer containing a // packed file and len is the length of the buffer. // If null, the callback is used to fill an internal buffer. void unpacker::start(void* packptr, size_t len) { + CHECK; NOT_PRODUCT(debug_u = this); if (packptr != null && len != 0) { inbytes.set((byte*) packptr, len); } + CHECK; read_bands(); } @@ -3735,6 +3743,7 @@ void unpacker::write_bc_ops() { NOT_PRODUCT(bc_superfield.setIndex(null)); NOT_PRODUCT(bc_supermethod.setIndex(null)); } + CHECK; for (int curIP = 0; ; curIP++) { int curPC = wpoffset() - codeBase; @@ -3760,196 +3769,197 @@ void unpacker::write_bc_ops() { case bc_tableswitch: // apc: (df, lo, hi, (hi-lo+1)*(label)) case bc_lookupswitch: // apc: (df, nc, nc*(case, label)) { - int caseCount = bc_case_count.getInt(); - while (((wpoffset() - codeBase) % 4) != 0) putu1_fast(0); - ensure_put_space(30 + caseCount*8); - put_label(curIP, 4); //int df = bc_label.getInt(); - if (bc == bc_tableswitch) { - int lo = bc_case_value.getInt(); - int hi = lo + caseCount-1; - putu4(lo); - putu4(hi); - for (int j = 0; j < caseCount; j++) { - put_label(curIP, 4); //int lVal = bc_label.getInt(); - //int cVal = lo + j; - } - } else { - putu4(caseCount); - for (int j = 0; j < caseCount; j++) { - int cVal = bc_case_value.getInt(); - putu4(cVal); - put_label(curIP, 4); //int lVal = bc_label.getInt(); - } - } - assert(to_bci(curIP) == curPC); - continue; + int caseCount = bc_case_count.getInt(); + while (((wpoffset() - codeBase) % 4) != 0) putu1_fast(0); + ensure_put_space(30 + caseCount*8); + put_label(curIP, 4); //int df = bc_label.getInt(); + if (bc == bc_tableswitch) { + int lo = bc_case_value.getInt(); + int hi = lo + caseCount-1; + putu4(lo); + putu4(hi); + for (int j = 0; j < caseCount; j++) { + put_label(curIP, 4); //int lVal = bc_label.getInt(); + //int cVal = lo + j; + } + } else { + putu4(caseCount); + for (int j = 0; j < caseCount; j++) { + int cVal = bc_case_value.getInt(); + putu4(cVal); + put_label(curIP, 4); //int lVal = bc_label.getInt(); + } + } + assert(to_bci(curIP) == curPC); + continue; } case bc_iinc: { - int local = bc_local.getInt(); - int delta = (isWide ? bc_short : bc_byte).getInt(); - if (isWide) { - putu2(local); - putu2(delta); - } else { - putu1_fast(local); - putu1_fast(delta); - } - continue; + int local = bc_local.getInt(); + int delta = (isWide ? bc_short : bc_byte).getInt(); + if (isWide) { + putu2(local); + putu2(delta); + } else { + putu1_fast(local); + putu1_fast(delta); + } + continue; } case bc_sipush: { - int val = bc_short.getInt(); - putu2(val); - continue; + int val = bc_short.getInt(); + putu2(val); + continue; } case bc_bipush: case bc_newarray: { - int val = bc_byte.getByte(); - putu1_fast(val); - continue; + int val = bc_byte.getByte(); + putu1_fast(val); + continue; } case bc_ref_escape: { - // Note that insnMap has one entry for this. + // Note that insnMap has one entry for this. --wp; // not really part of the code - int size = bc_escrefsize.getInt(); - entry* ref = bc_escref.getRefN(); - CHECK; - switch (size) { - case 1: putu1ref(ref); break; - case 2: putref(ref); break; - default: assert(false); - } - continue; + int size = bc_escrefsize.getInt(); + entry* ref = bc_escref.getRefN(); + CHECK; + switch (size) { + case 1: putu1ref(ref); break; + case 2: putref(ref); break; + default: assert(false); + } + continue; } case bc_byte_escape: { - // Note that insnMap has one entry for all these bytes. + // Note that insnMap has one entry for all these bytes. --wp; // not really part of the code - int size = bc_escsize.getInt(); - ensure_put_space(size); - for (int j = 0; j < size; j++) - putu1_fast(bc_escbyte.getByte()); - continue; + int size = bc_escsize.getInt(); + ensure_put_space(size); + for (int j = 0; j < size; j++) + putu1_fast(bc_escbyte.getByte()); + continue; } default: if (is_invoke_init_op(bc)) { - origBC = bc_invokespecial; - entry* classRef; - switch (bc - _invokeinit_op) { - case _invokeinit_self_option: classRef = thisClass; break; - case _invokeinit_super_option: classRef = superClass; break; - default: assert(bc == _invokeinit_op+_invokeinit_new_option); - case _invokeinit_new_option: classRef = newClass; break; - } - wp[-1] = origBC; // overwrite with origBC - int coding = bc_initref.getInt(); - // Find the nth overloading of in classRef. - entry* ref = null; - cpindex* ix = (classRef == null)? null: cp.getMethodIndex(classRef); - for (int j = 0, which_init = 0; ; j++) { - ref = (ix == null)? null: ix->get(j); - if (ref == null) break; // oops, bad input - assert(ref->tag == CONSTANT_Methodref); - if (ref->memberDescr()->descrName() == cp.sym[cpool::s_lt_init_gt]) { - if (which_init++ == coding) break; - } - } - putref(ref); - continue; + origBC = bc_invokespecial; + entry* classRef; + switch (bc - _invokeinit_op) { + case _invokeinit_self_option: classRef = thisClass; break; + case _invokeinit_super_option: classRef = superClass; break; + default: assert(bc == _invokeinit_op+_invokeinit_new_option); + case _invokeinit_new_option: classRef = newClass; break; + } + wp[-1] = origBC; // overwrite with origBC + int coding = bc_initref.getInt(); + // Find the nth overloading of in classRef. + entry* ref = null; + cpindex* ix = cp.getMethodIndex(classRef); + CHECK; + for (int j = 0, which_init = 0; ; j++) { + ref = (ix == null)? null: ix->get(j); + if (ref == null) break; // oops, bad input + assert(ref->tag == CONSTANT_Methodref); + if (ref->memberDescr()->descrName() == cp.sym[cpool::s_lt_init_gt]) { + if (which_init++ == coding) break; + } + } + putref(ref); + continue; } bc_which = ref_band_for_self_op(bc, isAload, origBC); if (bc_which != null) { - if (!isAload) { - wp[-1] = origBC; // overwrite with origBC - } else { - wp[-1] = bc_aload_0; // overwrite with _aload_0 - // Note: insnMap keeps the _aload_0 separate. - bcimap.add(++curPC); - ++curIP; - putu1_fast(origBC); - } - entry* ref = bc_which->getRef(); - CHECK; - putref(ref); - continue; + if (!isAload) { + wp[-1] = origBC; // overwrite with origBC + } else { + wp[-1] = bc_aload_0; // overwrite with _aload_0 + // Note: insnMap keeps the _aload_0 separate. + bcimap.add(++curPC); + ++curIP; + putu1_fast(origBC); + } + entry* ref = bc_which->getRef(); + CHECK; + putref(ref); + continue; } if (is_branch_op(bc)) { - //int lVal = bc_label.getInt(); - if (bc < bc_goto_w) { - put_label(curIP, 2); //putu2(lVal & 0xFFFF); - } else { - assert(bc <= bc_jsr_w); - put_label(curIP, 4); //putu4(lVal); - } - assert(to_bci(curIP) == curPC); - continue; + //int lVal = bc_label.getInt(); + if (bc < bc_goto_w) { + put_label(curIP, 2); //putu2(lVal & 0xFFFF); + } else { + assert(bc <= bc_jsr_w); + put_label(curIP, 4); //putu4(lVal); + } + assert(to_bci(curIP) == curPC); + continue; } bc_which = ref_band_for_op(bc); if (bc_which != null) { - entry* ref = bc_which->getRefCommon(bc_which->ix, bc_which->nullOK); - CHECK; - if (ref == null && bc_which == &bc_classref) { - // Shorthand for class self-references. - ref = thisClass; - } - origBC = bc; - switch (bc) { - case bc_ildc: - case bc_cldc: - case bc_fldc: - case bc_aldc: - origBC = bc_ldc; - break; - case bc_ildc_w: - case bc_cldc_w: - case bc_fldc_w: - case bc_aldc_w: - origBC = bc_ldc_w; - break; - case bc_lldc2_w: - case bc_dldc2_w: - origBC = bc_ldc2_w; - break; - case bc_new: - newClass = ref; - break; - } - wp[-1] = origBC; // overwrite with origBC - if (origBC == bc_ldc) { - putu1ref(ref); - } else { - putref(ref); - } - if (origBC == bc_multianewarray) { - // Copy the trailing byte also. - int val = bc_byte.getByte(); - putu1_fast(val); - } else if (origBC == bc_invokeinterface) { - int argSize = ref->memberDescr()->descrType()->typeSize(); - putu1_fast(1 + argSize); - putu1_fast(0); - } - continue; + entry* ref = bc_which->getRefCommon(bc_which->ix, bc_which->nullOK); + CHECK; + if (ref == null && bc_which == &bc_classref) { + // Shorthand for class self-references. + ref = thisClass; + } + origBC = bc; + switch (bc) { + case bc_ildc: + case bc_cldc: + case bc_fldc: + case bc_aldc: + origBC = bc_ldc; + break; + case bc_ildc_w: + case bc_cldc_w: + case bc_fldc_w: + case bc_aldc_w: + origBC = bc_ldc_w; + break; + case bc_lldc2_w: + case bc_dldc2_w: + origBC = bc_ldc2_w; + break; + case bc_new: + newClass = ref; + break; + } + wp[-1] = origBC; // overwrite with origBC + if (origBC == bc_ldc) { + putu1ref(ref); + } else { + putref(ref); + } + if (origBC == bc_multianewarray) { + // Copy the trailing byte also. + int val = bc_byte.getByte(); + putu1_fast(val); + } else if (origBC == bc_invokeinterface) { + int argSize = ref->memberDescr()->descrType()->typeSize(); + putu1_fast(1 + argSize); + putu1_fast(0); + } + continue; } if (is_local_slot_op(bc)) { - int local = bc_local.getInt(); - if (isWide) { - putu2(local); - if (bc == bc_iinc) { - int iVal = bc_short.getInt(); - putu2(iVal); - } - } else { - putu1_fast(local); - if (bc == bc_iinc) { - int iVal = bc_byte.getByte(); - putu1_fast(iVal); - } - } - continue; + int local = bc_local.getInt(); + if (isWide) { + putu2(local); + if (bc == bc_iinc) { + int iVal = bc_short.getInt(); + putu2(iVal); + } + } else { + putu1_fast(local); + if (bc == bc_iinc) { + int iVal = bc_byte.getByte(); + putu1_fast(iVal); + } + } + continue; } // Random bytecode. Just copy it. assert(bc < bc_bytecode_limit); @@ -4073,78 +4083,80 @@ int unpacker::write_attrs(int attrc, jul case ADH_BYTE(ATTR_CONTEXT_FIELD, X_ATTR_OVERFLOW): case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_OVERFLOW): case ADH_BYTE(ATTR_CONTEXT_CODE, X_ATTR_OVERFLOW): - // no attribute at all, so back up on this one - wp = wp_at(abase); - continue; + // no attribute at all, so back up on this one + wp = wp_at(abase); + continue; case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_ClassFile_version): - cur_class_minver = class_ClassFile_version_minor_H.getInt(); - cur_class_majver = class_ClassFile_version_major_H.getInt(); - // back up; not a real attribute - wp = wp_at(abase); - continue; + cur_class_minver = class_ClassFile_version_minor_H.getInt(); + cur_class_majver = class_ClassFile_version_major_H.getInt(); + // back up; not a real attribute + wp = wp_at(abase); + continue; case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_InnerClasses): - // note the existence of this attr, but save for later - if (cur_class_has_local_ics) - abort("too many InnerClasses attrs"); - cur_class_has_local_ics = true; - wp = wp_at(abase); - continue; + // note the existence of this attr, but save for later + if (cur_class_has_local_ics) + abort("too many InnerClasses attrs"); + cur_class_has_local_ics = true; + wp = wp_at(abase); + continue; case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_SourceFile): - aname = cp.sym[cpool::s_SourceFile]; - ref = class_SourceFile_RUN.getRefN(); - CHECK_0; - if (ref == null) { - bytes& n = cur_class->ref(0)->value.b; - // parse n = (/)*?($)* - int pkglen = lastIndexOf(SLASH_MIN, SLASH_MAX, n, n.len)+1; - bytes prefix = n.slice(pkglen, n.len); - for (;;) { - // Work backwards, finding all '$', '#', etc. - int dollar = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, prefix, prefix.len); - if (dollar < 0) break; - prefix = prefix.slice(0, dollar); - } - const char* suffix = ".java"; - int len = prefix.len + strlen(suffix); - bytes name; name.set(T_NEW(byte, add_size(len, 1)), len); - name.strcat(prefix).strcat(suffix); - ref = cp.ensureUtf8(name); - } - putref(ref); - break; + aname = cp.sym[cpool::s_SourceFile]; + ref = class_SourceFile_RUN.getRefN(); + CHECK_0; + if (ref == null) { + bytes& n = cur_class->ref(0)->value.b; + // parse n = (/)*?($)* + int pkglen = lastIndexOf(SLASH_MIN, SLASH_MAX, n, n.len)+1; + bytes prefix = n.slice(pkglen, n.len); + for (;;) { + // Work backwards, finding all '$', '#', etc. + int dollar = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, prefix, prefix.len); + if (dollar < 0) break; + prefix = prefix.slice(0, dollar); + } + const char* suffix = ".java"; + int len = prefix.len + strlen(suffix); + bytes name; name.set(T_NEW(byte, add_size(len, 1)), len); + name.strcat(prefix).strcat(suffix); + ref = cp.ensureUtf8(name); + } + putref(ref); + break; case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_EnclosingMethod): - aname = cp.sym[cpool::s_EnclosingMethod]; - putref(class_EnclosingMethod_RC.getRefN()); - putref(class_EnclosingMethod_RDN.getRefN()); - break; + aname = cp.sym[cpool::s_EnclosingMethod]; + putref(class_EnclosingMethod_RC.getRefN()); + CHECK_0; + putref(class_EnclosingMethod_RDN.getRefN()); + break; case ADH_BYTE(ATTR_CONTEXT_FIELD, FIELD_ATTR_ConstantValue): - aname = cp.sym[cpool::s_ConstantValue]; - putref(field_ConstantValue_KQ.getRefUsing(cp.getKQIndex())); - break; + aname = cp.sym[cpool::s_ConstantValue]; + putref(field_ConstantValue_KQ.getRefUsing(cp.getKQIndex())); + break; case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_Code): - aname = cp.sym[cpool::s_Code]; - write_code(); - break; + aname = cp.sym[cpool::s_Code]; + write_code(); + break; case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_Exceptions): - aname = cp.sym[cpool::s_Exceptions]; - putu2(count = method_Exceptions_N.getInt()); - for (j = 0; j < count; j++) { - putref(method_Exceptions_RC.getRefN()); - } - break; + aname = cp.sym[cpool::s_Exceptions]; + putu2(count = method_Exceptions_N.getInt()); + for (j = 0; j < count; j++) { + putref(method_Exceptions_RC.getRefN()); + CHECK_0; + } + break; case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_StackMapTable): - aname = cp.sym[cpool::s_StackMapTable]; + aname = cp.sym[cpool::s_StackMapTable]; // (keep this code aligned with its brother in unpacker::read_attrs) - putu2(count = code_StackMapTable_N.getInt()); - for (j = 0; j < count; j++) { + putu2(count = code_StackMapTable_N.getInt()); + for (j = 0; j < count; j++) { int tag = code_StackMapTable_frame_T.getByte(); putu1(tag); if (tag <= 127) { @@ -4160,109 +4172,115 @@ int unpacker::write_attrs(int attrc, jul // (253) [(1)(2)(2)] // (254) [(1)(2)(2)(2)] putu2(code_StackMapTable_offset.getInt()); + CHECK_0; for (int j2 = (tag - 251); j2 > 0; j2--) { put_stackmap_type(); + CHECK_0; } } else { // (255) [(1)NH[(2)]NH[(2)]] putu2(code_StackMapTable_offset.getInt()); putu2(j2 = code_StackMapTable_local_N.getInt()); - while (j2-- > 0) put_stackmap_type(); + while (j2-- > 0) {put_stackmap_type(); CHECK_0;} putu2(j2 = code_StackMapTable_stack_N.getInt()); - while (j2-- > 0) put_stackmap_type(); + while (j2-- > 0) {put_stackmap_type(); CHECK_0;} } - } - break; + } + break; case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LineNumberTable): - aname = cp.sym[cpool::s_LineNumberTable]; - putu2(count = code_LineNumberTable_N.getInt()); - for (j = 0; j < count; j++) { - putu2(to_bci(code_LineNumberTable_bci_P.getInt())); - putu2(code_LineNumberTable_line.getInt()); - } - break; + aname = cp.sym[cpool::s_LineNumberTable]; + putu2(count = code_LineNumberTable_N.getInt()); + for (j = 0; j < count; j++) { + putu2(to_bci(code_LineNumberTable_bci_P.getInt())); + putu2(code_LineNumberTable_line.getInt()); + } + break; case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LocalVariableTable): - aname = cp.sym[cpool::s_LocalVariableTable]; - putu2(count = code_LocalVariableTable_N.getInt()); - for (j = 0; j < count; j++) { - int bii = code_LocalVariableTable_bci_P.getInt(); - int bci = to_bci(bii); - putu2(bci); - bii += code_LocalVariableTable_span_O.getInt(); - putu2(to_bci(bii) - bci); - putref(code_LocalVariableTable_name_RU.getRefN()); - putref(code_LocalVariableTable_type_RS.getRefN()); - putu2(code_LocalVariableTable_slot.getInt()); - } - break; + aname = cp.sym[cpool::s_LocalVariableTable]; + putu2(count = code_LocalVariableTable_N.getInt()); + for (j = 0; j < count; j++) { + int bii = code_LocalVariableTable_bci_P.getInt(); + int bci = to_bci(bii); + putu2(bci); + bii += code_LocalVariableTable_span_O.getInt(); + putu2(to_bci(bii) - bci); + putref(code_LocalVariableTable_name_RU.getRefN()); + CHECK_0; + putref(code_LocalVariableTable_type_RS.getRefN()); + CHECK_0; + putu2(code_LocalVariableTable_slot.getInt()); + } + break; case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LocalVariableTypeTable): - aname = cp.sym[cpool::s_LocalVariableTypeTable]; - putu2(count = code_LocalVariableTypeTable_N.getInt()); - for (j = 0; j < count; j++) { - int bii = code_LocalVariableTypeTable_bci_P.getInt(); - int bci = to_bci(bii); - putu2(bci); - bii += code_LocalVariableTypeTable_span_O.getInt(); - putu2(to_bci(bii) - bci); - putref(code_LocalVariableTypeTable_name_RU.getRefN()); - putref(code_LocalVariableTypeTable_type_RS.getRefN()); - putu2(code_LocalVariableTypeTable_slot.getInt()); - } - break; + aname = cp.sym[cpool::s_LocalVariableTypeTable]; + putu2(count = code_LocalVariableTypeTable_N.getInt()); + for (j = 0; j < count; j++) { + int bii = code_LocalVariableTypeTable_bci_P.getInt(); + int bci = to_bci(bii); + putu2(bci); + bii += code_LocalVariableTypeTable_span_O.getInt(); + putu2(to_bci(bii) - bci); + putref(code_LocalVariableTypeTable_name_RU.getRefN()); + CHECK_0; + putref(code_LocalVariableTypeTable_type_RS.getRefN()); + CHECK_0; + putu2(code_LocalVariableTypeTable_slot.getInt()); + } + break; case ADH_BYTE(ATTR_CONTEXT_CLASS, X_ATTR_Signature): - aname = cp.sym[cpool::s_Signature]; - putref(class_Signature_RS.getRefN()); - break; + aname = cp.sym[cpool::s_Signature]; + putref(class_Signature_RS.getRefN()); + break; case ADH_BYTE(ATTR_CONTEXT_FIELD, X_ATTR_Signature): - aname = cp.sym[cpool::s_Signature]; - putref(field_Signature_RS.getRefN()); - break; + aname = cp.sym[cpool::s_Signature]; + putref(field_Signature_RS.getRefN()); + break; case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_Signature): - aname = cp.sym[cpool::s_Signature]; - putref(method_Signature_RS.getRefN()); - break; + aname = cp.sym[cpool::s_Signature]; + putref(method_Signature_RS.getRefN()); + break; case ADH_BYTE(ATTR_CONTEXT_CLASS, X_ATTR_Deprecated): case ADH_BYTE(ATTR_CONTEXT_FIELD, X_ATTR_Deprecated): case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_Deprecated): - aname = cp.sym[cpool::s_Deprecated]; - // no data - break; - } - } - + aname = cp.sym[cpool::s_Deprecated]; + // no data + break; + } + } + CHECK_0; if (aname == null) { // Unparse a compressor-defined attribute. layout_definition* lo = ad.getLayout(idx); if (lo == null) { - abort("bad layout index"); - break; + abort("bad layout index"); + break; } assert(lo->idx == idx); aname = lo->nameEntry; if (aname == null) { - bytes nameb; nameb.set(lo->name); - aname = cp.ensureUtf8(nameb); - // Cache the name entry for next time. - lo->nameEntry = aname; + bytes nameb; nameb.set(lo->name); + aname = cp.ensureUtf8(nameb); + // Cache the name entry for next time. + lo->nameEntry = aname; } // Execute all the layout elements. band** bands = lo->bands(); if (lo->hasCallables()) { - band& cble = *bands[0]; - assert(cble.le_kind == EK_CBLE); - bands = cble.le_body; + band& cble = *bands[0]; + assert(cble.le_kind == EK_CBLE); + bands = cble.le_body; } putlayout(bands); } - if (aname == null) + if (aname == null) abort("bad attribute index"); CHECK_0; @@ -4335,8 +4353,8 @@ void unpacker::write_classfile_tail() { julong indexMask = ad.flagIndexMask(); cur_class = class_this.getRef(); + CHECK; cur_super = class_super.getRef(); - CHECK; if (cur_super == cur_class) cur_super = null; @@ -4349,6 +4367,7 @@ void unpacker::write_classfile_tail() { putu2(num = class_interface_count.getInt()); for (i = 0; i < num; i++) { putref(class_interface.getRef()); + CHECK; } write_members(class_field_count.getInt(), ATTR_CONTEXT_FIELD); @@ -4389,8 +4408,8 @@ void unpacker::write_classfile_tail() { entry& e = *oes[i]; if (e.tag != CONSTANT_Class) continue; // wrong sort for (inner_class* ic = cp.getIC(&e); - ic != null; - ic = cp.getIC(ic->outer)) { + ic != null; + ic = cp.getIC(ic->outer)) { if (ic->requested) break; // already processed ic->requested = true; requested_ics.add(ic); @@ -4421,22 +4440,24 @@ void unpacker::write_classfile_tail() { if (flags == 0) { // The extra IC is simply a copy of a global IC. if (global_ic == null) { - abort("bad reference to inner class"); - break; + abort("bad reference to inner class"); + break; } extra_ic = (*global_ic); // fill in rest of fields } else { flags &= ~ACC_IC_LONG_FORM; // clear high bit if set to get clean zero extra_ic.flags = flags; extra_ic.outer = class_InnerClasses_outer_RCN.getRefN(); + CHECK; extra_ic.name = class_InnerClasses_name_RUN.getRefN(); + CHECK; // Detect if this is an exact copy of the global tuple. if (global_ic != null) { - if (global_ic->flags != extra_ic.flags || - global_ic->outer != extra_ic.outer || - global_ic->name != extra_ic.name) { - global_ic = null; // not really the same, so break the link - } + if (global_ic->flags != extra_ic.flags || + global_ic->outer != extra_ic.outer || + global_ic->name != extra_ic.name) { + global_ic = null; // not really the same, so break the link + } } } if (global_ic != null && global_ic->requested) { @@ -4465,15 +4486,15 @@ void unpacker::write_classfile_tail() { for (i = -num_global_ics; i < num_extra_ics; i++) { inner_class* ic; if (i < 0) - ic = (inner_class*) requested_ics.get(num_global_ics+i); + ic = (inner_class*) requested_ics.get(num_global_ics+i); else - ic = &extra_ics[i]; + ic = &extra_ics[i]; if (ic->requested) { - putref(ic->inner); - putref(ic->outer); - putref(ic->name); - putu2(ic->flags); - NOT_PRODUCT(local_ics--); + putref(ic->inner); + putref(ic->outer); + putref(ic->name); + putu2(ic->flags); + NOT_PRODUCT(local_ics--); } } assert(local_ics == 0); // must balance @@ -4573,7 +4594,7 @@ unpacker::file* unpacker::get_next_file( if (archive_size != 0) { julong predicted_size = unsized_bytes_read + archive_size; if (predicted_size != bytes_read) - abort("archive header had incorrect size"); + abort("archive header had incorrect size"); } return null; } @@ -4637,7 +4658,7 @@ unpacker::file* unpacker::get_next_file( size_t rpleft = input_remaining(); if (rpleft > 0) { if (rpleft > cur_file.size) - rpleft = (size_t) cur_file.size; + rpleft = (size_t) cur_file.size; cur_file.data[0].set(rp, rpleft); rp += rpleft; } @@ -4655,7 +4676,7 @@ unpacker::file* unpacker::get_next_file( // Write a file to jarout. void unpacker::write_file_to_jar(unpacker::file* f) { - size_t htsize = f->data[0].len + f->data[1].len; + size_t htsize = f->data[0].len + f->data[1].len; julong fsize = f->size; #ifndef PRODUCT if (nowrite NOT_PRODUCT(|| skipfiles-- > 0)) { @@ -4665,7 +4686,7 @@ void unpacker::write_file_to_jar(unpacke #endif if (htsize == fsize) { jarout->addJarEntry(f->name, f->deflate_hint(), f->modtime, - f->data[0], f->data[1]); + f->data[0], f->data[1]); } else { assert(input_remaining() == 0); bytes part1, part2; @@ -4680,27 +4701,27 @@ void unpacker::write_file_to_jar(unpacke if (fleft > 0) { // Must read some more. if (live_input) { - // Stop using the input buffer. Make a new one: - if (free_input) input.free(); - input.init(fleft > (1<<12) ? fleft : (1<<12)); - free_input = true; - live_input = false; + // Stop using the input buffer. Make a new one: + if (free_input) input.free(); + input.init(fleft > (1<<12) ? fleft : (1<<12)); + free_input = true; + live_input = false; } else { - // Make it large enough. - assert(free_input); // must be reallocable - input.ensureSize(fleft); + // Make it large enough. + assert(free_input); // must be reallocable + input.ensureSize(fleft); } rplimit = rp = input.base(); CHECK; input.setLimit(rp + fleft); if (!ensure_input(fleft)) - abort("EOF reading resource file"); + abort("EOF reading resource file"); part2.ptr = input_scan(); part2.len = input_remaining(); rplimit = rp = input.base(); } jarout->addJarEntry(f->name, f->deflate_hint(), f->modtime, - part1, part2); + part1, part2); } if (verbose >= 3) { fprintf(errstrm, "Wrote %lld bytes to: %s\n", fsize, f->name); @@ -4722,7 +4743,7 @@ void unpacker::redirect_stdio() { } else if (strcmp(log_file, LOGFILE_STDOUT) == 0) { errstrm = stdout; return; - } else if (log_file[0] != '\0' && (errstrm = fopen(log_file,"a+")) != NULL) { + } else if (log_file[0] != '\0' && (errstrm = fopen(log_file,"a+")) != NULL) { return; } else { char log_file_name[PATH_MAX+100]; @@ -4732,7 +4753,7 @@ void unpacker::redirect_stdio() { if (n < 1 || n > PATH_MAX) { sprintf(tmpdir,"C:\\"); } - sprintf(log_file_name, "%sunpack.log", tmpdir); + sprintf(log_file_name, "%sunpack.log", tmpdir); #else sprintf(tmpdir,"/tmp"); sprintf(log_file_name, "/tmp/unpack.log"); @@ -4742,7 +4763,7 @@ void unpacker::redirect_stdio() { return ; } - char *tname = tempnam(tmpdir,"#upkg"); + char *tname = tempnam(tmpdir,"#upkg"); sprintf(log_file_name, "%s", tname); if ((errstrm = fopen(log_file_name, "a+")) != NULL) { log_file = errstrm_name = saveStr(log_file_name); @@ -4758,7 +4779,7 @@ void unpacker::redirect_stdio() { #endif // Last resort // (Do not use stdout, since it might be jarout->jarfp.) - errstrm = stderr; + errstrm = stderr; log_file = errstrm_name = LOGFILE_STDERR; } } @@ -4799,3 +4820,5 @@ void unpacker::abort(const char* message #endif #endif // JNI } + +