Showing the changes to java/pkg/com/sun/java/util/jar/pack/BandStructure.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,2682 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 5 | * This code is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 only, as | ||
| 7 | * published by the Free Software Foundation. Oracle designates this | ||
| 8 | * particular file as subject to the "Classpath" exception as provided | ||
| 9 | * by Oracle in the LICENSE file that accompanied this code. | ||
| 10 | * | ||
| 11 | * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 14 | * version 2 for more details (a copy is included in the LICENSE file that | ||
| 15 | * accompanied this code). | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License version | ||
| 18 | * 2 along with this work; if not, write to the Free Software Foundation, | ||
| 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 20 | * | ||
| 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| 22 | * or visit www.oracle.com if you need additional information or have any | ||
| 23 | * questions. | ||
| 24 | */ | ||
| 25 | |||
| 26 | package com.sun.java.util.jar.pack; | ||
| 27 | |||
| 28 | import com.sun.java.util.jar.pack.ConstantPool.Entry; | ||
| 29 | import com.sun.java.util.jar.pack.ConstantPool.Index; | ||
| 30 | import com.sun.java.util.jar.pack.Package.Class.Field; | ||
| 31 | import java.io.BufferedOutputStream; | ||
| 32 | import java.io.ByteArrayInputStream; | ||
| 33 | import java.io.ByteArrayOutputStream; | ||
| 34 | import java.io.EOFException; | ||
| 35 | import java.io.File; | ||
| 36 | import java.io.FileOutputStream; | ||
| 37 | import java.io.FilterInputStream; | ||
| 38 | import java.io.FilterOutputStream; | ||
| 39 | import java.io.IOException; | ||
| 40 | import java.io.InputStream; | ||
| 41 | import java.io.OutputStream; | ||
| 42 | import java.io.PrintStream; | ||
| 43 | import java.util.ArrayList; | ||
| 44 | import java.util.Arrays; | ||
| 45 | import java.util.Collections; | ||
| 46 | import java.util.HashMap; | ||
| 47 | import java.util.List; | ||
| 48 | import java.util.Map; | ||
| 49 | import java.util.jar.Pack200; | ||
| 50 | import static com.sun.java.util.jar.pack.Constants.*; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Define the structure and ordering of "bands" in a packed file. | ||
| 54 | * @author John Rose | ||
| 55 | */ | ||
| 56 | abstract | ||
| 57 | class BandStructure { | ||
| 58 | static final int MAX_EFFORT = 9; | ||
| 59 | static final int MIN_EFFORT = 1; | ||
| 60 | static final int DEFAULT_EFFORT = 5; | ||
| 61 | |||
| 62 | // Inherit options from Pack200: | ||
| 63 | PropMap p200 = Utils.currentPropMap(); | ||
| 64 | |||
| 65 | int verbose = p200.getInteger(Utils.DEBUG_VERBOSE); | ||
| 66 | int effort = p200.getInteger(Pack200.Packer.EFFORT); | ||
| 67 | { if (effort == 0) effort = DEFAULT_EFFORT; } | ||
| 68 | boolean optDumpBands = p200.getBoolean(Utils.COM_PREFIX+"dump.bands"); | ||
| 69 | boolean optDebugBands = p200.getBoolean(Utils.COM_PREFIX+"debug.bands"); | ||
| 70 | |||
| 71 | // Various heuristic options. | ||
| 72 | boolean optVaryCodings = !p200.getBoolean(Utils.COM_PREFIX+"no.vary.codings"); | ||
| 73 | boolean optBigStrings = !p200.getBoolean(Utils.COM_PREFIX+"no.big.strings"); | ||
| 74 | |||
| 75 | abstract protected Index getCPIndex(byte tag); | ||
| 76 | |||
| 77 | // Local copy of package version. | ||
| 78 | private int packageMajver = -1; | ||
| 79 | |||
| 80 | /** Call this exactly once, early, to specify the archive major version. */ | ||
| 81 | public void initPackageMajver(int packageMajver) throws IOException { | ||
| 82 | assert(packageMajver > 0 && packageMajver < 0x10000); | ||
| 83 | if (this.packageMajver > 0) { | ||
| 84 | throw new IOException( | ||
| 85 | "Package majver is already initialized to " + this.packageMajver+ | ||
| 86 | "; new setting is " + packageMajver); | ||
| 87 | } | ||
| 88 | this.packageMajver = packageMajver; | ||
| 89 | adjustToMajver(); | ||
| 90 | } | ||
| 91 | public int getPackageMajver() { | ||
| 92 | if (packageMajver < 0) { | ||
| 93 | throw new RuntimeException("Package majver not yet initialized"); | ||
| 94 | } | ||
| 95 | return packageMajver; | ||
| 96 | } | ||
| 97 | |||
| 98 | private final boolean isReader = this instanceof PackageReader; | ||
| 99 | protected BandStructure() { | ||
| 100 | } | ||
| 101 | |||
| 102 | final static Coding BYTE1 = Coding.of(1,256); | ||
| 103 | |||
| 104 | final static Coding CHAR3 = Coding.of(3,128); | ||
| 105 | // Note: Tried sharper (3,16) with no post-zip benefit. | ||
| 106 | |||
| 107 | // This is best used with BCI values: | ||
| 108 | final static Coding BCI5 = Coding.of(5,4); // mostly 1-byte offsets | ||
| 109 | final static Coding BRANCH5 = Coding.of(5,4,2); // mostly forward branches | ||
| 110 | |||
| 111 | final static Coding UNSIGNED5 = Coding.of(5,64); | ||
| 112 | final static Coding UDELTA5 = UNSIGNED5.getDeltaCoding(); | ||
| 113 | // "sharp" (5,64) zips 0.4% better than "medium" (5,128) | ||
| 114 | // It zips 1.1% better than "flat" (5,192) | ||
| 115 | |||
| 116 | final static Coding SIGNED5 = Coding.of(5,64,1); //sharp | ||
| 117 | final static Coding DELTA5 = SIGNED5.getDeltaCoding(); | ||
| 118 | // Note: Tried (5,128,2) and (5,192,2) with no benefit. | ||
| 119 | |||
| 120 | final static Coding MDELTA5 = Coding.of(5,64,2).getDeltaCoding(); | ||
| 121 | |||
| 122 | final private static Coding[] basicCodings = { | ||
| 123 | // Table of "Canonical BHSD Codings" from Pack200 spec. | ||
| 124 | null, // _meta_default | ||
| 125 | |||
| 126 | // Fixed-length codings: | ||
| 127 | Coding.of(1,256,0), | ||
| 128 | Coding.of(1,256,1), | ||
| 129 | Coding.of(1,256,0).getDeltaCoding(), | ||
| 130 | Coding.of(1,256,1).getDeltaCoding(), | ||
| 131 | Coding.of(2,256,0), | ||
| 132 | Coding.of(2,256,1), | ||
| 133 | Coding.of(2,256,0).getDeltaCoding(), | ||
| 134 | Coding.of(2,256,1).getDeltaCoding(), | ||
| 135 | Coding.of(3,256,0), | ||
| 136 | Coding.of(3,256,1), | ||
| 137 | Coding.of(3,256,0).getDeltaCoding(), | ||
| 138 | Coding.of(3,256,1).getDeltaCoding(), | ||
| 139 | Coding.of(4,256,0), | ||
| 140 | Coding.of(4,256,1), | ||
| 141 | Coding.of(4,256,0).getDeltaCoding(), | ||
| 142 | Coding.of(4,256,1).getDeltaCoding(), | ||
| 143 | |||
| 144 | // Full-range variable-length codings: | ||
| 145 | Coding.of(5, 4,0), | ||
| 146 | Coding.of(5, 4,1), | ||
| 147 | Coding.of(5, 4,2), | ||
| 148 | Coding.of(5, 16,0), | ||
| 149 | Coding.of(5, 16,1), | ||
| 150 | Coding.of(5, 16,2), | ||
| 151 | Coding.of(5, 32,0), | ||
| 152 | Coding.of(5, 32,1), | ||
| 153 | Coding.of(5, 32,2), | ||
| 154 | Coding.of(5, 64,0), | ||
| 155 | Coding.of(5, 64,1), | ||
| 156 | Coding.of(5, 64,2), | ||
| 157 | Coding.of(5,128,0), | ||
| 158 | Coding.of(5,128,1), | ||
| 159 | Coding.of(5,128,2), | ||
| 160 | |||
| 161 | Coding.of(5, 4,0).getDeltaCoding(), | ||
| 162 | Coding.of(5, 4,1).getDeltaCoding(), | ||
| 163 | Coding.of(5, 4,2).getDeltaCoding(), | ||
| 164 | Coding.of(5, 16,0).getDeltaCoding(), | ||
| 165 | Coding.of(5, 16,1).getDeltaCoding(), | ||
| 166 | Coding.of(5, 16,2).getDeltaCoding(), | ||
| 167 | Coding.of(5, 32,0).getDeltaCoding(), | ||
| 168 | Coding.of(5, 32,1).getDeltaCoding(), | ||
| 169 | Coding.of(5, 32,2).getDeltaCoding(), | ||
| 170 | Coding.of(5, 64,0).getDeltaCoding(), | ||
| 171 | Coding.of(5, 64,1).getDeltaCoding(), | ||
| 172 | Coding.of(5, 64,2).getDeltaCoding(), | ||
| 173 | Coding.of(5,128,0).getDeltaCoding(), | ||
| 174 | Coding.of(5,128,1).getDeltaCoding(), | ||
| 175 | Coding.of(5,128,2).getDeltaCoding(), | ||
| 176 | |||
| 177 | // Variable length subrange codings: | ||
| 178 | Coding.of(2,192,0), | ||
| 179 | Coding.of(2,224,0), | ||
| 180 | Coding.of(2,240,0), | ||
| 181 | Coding.of(2,248,0), | ||
| 182 | Coding.of(2,252,0), | ||
| 183 | |||
| 184 | Coding.of(2, 8,0).getDeltaCoding(), | ||
| 185 | Coding.of(2, 8,1).getDeltaCoding(), | ||
| 186 | Coding.of(2, 16,0).getDeltaCoding(), | ||
| 187 | Coding.of(2, 16,1).getDeltaCoding(), | ||
| 188 | Coding.of(2, 32,0).getDeltaCoding(), | ||
| 189 | Coding.of(2, 32,1).getDeltaCoding(), | ||
| 190 | Coding.of(2, 64,0).getDeltaCoding(), | ||
| 191 | Coding.of(2, 64,1).getDeltaCoding(), | ||
| 192 | Coding.of(2,128,0).getDeltaCoding(), | ||
| 193 | Coding.of(2,128,1).getDeltaCoding(), | ||
| 194 | Coding.of(2,192,0).getDeltaCoding(), | ||
| 195 | Coding.of(2,192,1).getDeltaCoding(), | ||
| 196 | Coding.of(2,224,0).getDeltaCoding(), | ||
| 197 | Coding.of(2,224,1).getDeltaCoding(), | ||
| 198 | Coding.of(2,240,0).getDeltaCoding(), | ||
| 199 | Coding.of(2,240,1).getDeltaCoding(), | ||
| 200 | Coding.of(2,248,0).getDeltaCoding(), | ||
| 201 | Coding.of(2,248,1).getDeltaCoding(), | ||
| 202 | |||
| 203 | Coding.of(3,192,0), | ||
| 204 | Coding.of(3,224,0), | ||
| 205 | Coding.of(3,240,0), | ||
| 206 | Coding.of(3,248,0), | ||
| 207 | Coding.of(3,252,0), | ||
| 208 | |||
| 209 | Coding.of(3, 8,0).getDeltaCoding(), | ||
| 210 | Coding.of(3, 8,1).getDeltaCoding(), | ||
| 211 | Coding.of(3, 16,0).getDeltaCoding(), | ||
| 212 | Coding.of(3, 16,1).getDeltaCoding(), | ||
| 213 | Coding.of(3, 32,0).getDeltaCoding(), | ||
| 214 | Coding.of(3, 32,1).getDeltaCoding(), | ||
| 215 | Coding.of(3, 64,0).getDeltaCoding(), | ||
| 216 | Coding.of(3, 64,1).getDeltaCoding(), | ||
| 217 | Coding.of(3,128,0).getDeltaCoding(), | ||
| 218 | Coding.of(3,128,1).getDeltaCoding(), | ||
| 219 | Coding.of(3,192,0).getDeltaCoding(), | ||
| 220 | Coding.of(3,192,1).getDeltaCoding(), | ||
| 221 | Coding.of(3,224,0).getDeltaCoding(), | ||
| 222 | Coding.of(3,224,1).getDeltaCoding(), | ||
| 223 | Coding.of(3,240,0).getDeltaCoding(), | ||
| 224 | Coding.of(3,240,1).getDeltaCoding(), | ||
| 225 | Coding.of(3,248,0).getDeltaCoding(), | ||
| 226 | Coding.of(3,248,1).getDeltaCoding(), | ||
| 227 | |||
| 228 | Coding.of(4,192,0), | ||
| 229 | Coding.of(4,224,0), | ||
| 230 | Coding.of(4,240,0), | ||
| 231 | Coding.of(4,248,0), | ||
| 232 | Coding.of(4,252,0), | ||
| 233 | |||
| 234 | Coding.of(4, 8,0).getDeltaCoding(), | ||
| 235 | Coding.of(4, 8,1).getDeltaCoding(), | ||
| 236 | Coding.of(4, 16,0).getDeltaCoding(), | ||
| 237 | Coding.of(4, 16,1).getDeltaCoding(), | ||
| 238 | Coding.of(4, 32,0).getDeltaCoding(), | ||
| 239 | Coding.of(4, 32,1).getDeltaCoding(), | ||
| 240 | Coding.of(4, 64,0).getDeltaCoding(), | ||
| 241 | Coding.of(4, 64,1).getDeltaCoding(), | ||
| 242 | Coding.of(4,128,0).getDeltaCoding(), | ||
| 243 | Coding.of(4,128,1).getDeltaCoding(), | ||
| 244 | Coding.of(4,192,0).getDeltaCoding(), | ||
| 245 | Coding.of(4,192,1).getDeltaCoding(), | ||
| 246 | Coding.of(4,224,0).getDeltaCoding(), | ||
| 247 | Coding.of(4,224,1).getDeltaCoding(), | ||
| 248 | Coding.of(4,240,0).getDeltaCoding(), | ||
| 249 | Coding.of(4,240,1).getDeltaCoding(), | ||
| 250 | Coding.of(4,248,0).getDeltaCoding(), | ||
| 251 | Coding.of(4,248,1).getDeltaCoding(), | ||
| 252 | |||
| 253 | null | ||
| 254 | }; | ||
| 255 | final private static Map<Coding, Integer> basicCodingIndexes; | ||
| 256 | static { | ||
| 257 | assert(basicCodings[_meta_default] == null); | ||
| 258 | assert(basicCodings[_meta_canon_min] != null); | ||
| 259 | assert(basicCodings[_meta_canon_max] != null); | ||
| 260 | Map<Coding, Integer> map = new HashMap<>(); | ||
| 261 | for (int i = 0; i < basicCodings.length; i++) { | ||
| 262 | Coding c = basicCodings[i]; | ||
| 263 | if (c == null) continue; | ||
| 264 | assert(i >= _meta_canon_min); | ||
| 265 | assert(i <= _meta_canon_max); | ||
| 266 | map.put(c, i); | ||
| 267 | } | ||
| 268 | basicCodingIndexes = map; | ||
| 269 | } | ||
| 270 | public static Coding codingForIndex(int i) { | ||
| 271 | return i < basicCodings.length ? basicCodings[i] : null; | ||
| 272 | } | ||
| 273 | public static int indexOf(Coding c) { | ||
| 274 | Integer i = basicCodingIndexes.get(c); | ||
| 275 | if (i == null) return 0; | ||
| 276 | return i.intValue(); | ||
| 277 | } | ||
| 278 | public static Coding[] getBasicCodings() { | ||
| 279 | return basicCodings.clone(); | ||
| 280 | } | ||
| 281 | |||
| 282 | protected byte[] bandHeaderBytes; // used for input only | ||
| 283 | protected int bandHeaderBytePos; // BHB read pointer, for input only | ||
| 284 | protected int bandHeaderBytePos0; // for debug | ||
| 285 | |||
| 286 | protected CodingMethod getBandHeader(int XB, Coding regularCoding) { | ||
| 287 | CodingMethod[] res = {null}; | ||
| 288 | // push back XB onto the band header bytes | ||
| 289 | bandHeaderBytes[--bandHeaderBytePos] = (byte) XB; | ||
| 290 | bandHeaderBytePos0 = bandHeaderBytePos; | ||
| 291 | // scan forward through XB and any additional band header bytes | ||
| 292 | bandHeaderBytePos = parseMetaCoding(bandHeaderBytes, | ||
| 293 | bandHeaderBytePos, | ||
| 294 | regularCoding, | ||
| 295 | res); | ||
| 296 | return res[0]; | ||
| 297 | } | ||
| 298 | |||
| 299 | public static int parseMetaCoding(byte[] bytes, int pos, Coding dflt, CodingMethod[] res) { | ||
| 300 | if ((bytes[pos] & 0xFF) == _meta_default) { | ||
| 301 | res[0] = dflt; | ||
| 302 | return pos+1; | ||
| 303 | } | ||
| 304 | int pos2; | ||
| 305 | pos2 = Coding.parseMetaCoding(bytes, pos, dflt, res); | ||
| 306 | if (pos2 > pos) return pos2; | ||
| 307 | pos2 = PopulationCoding.parseMetaCoding(bytes, pos, dflt, res); | ||
| 308 | if (pos2 > pos) return pos2; | ||
| 309 | pos2 = AdaptiveCoding.parseMetaCoding(bytes, pos, dflt, res); | ||
| 310 | if (pos2 > pos) return pos2; | ||
| 311 | throw new RuntimeException("Bad meta-coding op "+(bytes[pos]&0xFF)); | ||
| 312 | } | ||
| 313 | |||
| 314 | static final int SHORT_BAND_HEURISTIC = 100; | ||
| 315 | |||
| 316 | public static final int NO_PHASE = 0; | ||
| 317 | |||
| 318 | // package writing phases: | ||
| 319 | public static final int COLLECT_PHASE = 1; // collect data before write | ||
| 320 | public static final int FROZEN_PHASE = 3; // no longer collecting | ||
| 321 | public static final int WRITE_PHASE = 5; // ready to write bytes | ||
| 322 | |||
| 323 | // package reading phases: | ||
| 324 | public static final int EXPECT_PHASE = 2; // gather expected counts | ||
| 325 | public static final int READ_PHASE = 4; // ready to read bytes | ||
| 326 | public static final int DISBURSE_PHASE = 6; // pass out data after read | ||
| 327 | |||
| 328 | public static final int DONE_PHASE = 8; // done writing or reading | ||
| 329 | |||
| 330 | static boolean phaseIsRead(int p) { | ||
| 331 | return (p % 2) == 0; | ||
| 332 | } | ||
| 333 | static int phaseCmp(int p0, int p1) { | ||
| 334 | assert((p0 % 2) == (p1 % 2) || (p0 % 8) == 0 || (p1 % 8) == 0); | ||
| 335 | return p0 - p1; | ||
| 336 | } | ||
| 337 | |||
| 338 | /** The packed file is divided up into a number of segments. | ||
| 339 | * Most segments are typed as ValueBand, strongly-typed sequences | ||
| 340 | * of integer values, all interpreted in a single way. | ||
| 341 | * A few segments are ByteBands, which hetergeneous sequences | ||
| 342 | * of bytes. | ||
| 343 | * | ||
| 344 | * The two phases for writing a packed file are COLLECT and WRITE. | ||
| 345 | * 1. When writing a packed file, each band collects | ||
| 346 | * data in an ad-hoc order. | ||
| 347 | * 2. At the end, each band is assigned a coding scheme, | ||
| 348 | * and then all the bands are written in their global order. | ||
| 349 | * | ||
| 350 | * The three phases for reading a packed file are EXPECT, READ, | ||
| 351 | * and DISBURSE. | ||
| 352 | * 1. For each band, the expected number of integers is determined. | ||
| 353 | * 2. The data is actually read from the file into the band. | ||
| 354 | * 3. The band pays out its values as requested, in an ad hoc order. | ||
| 355 | * | ||
| 356 | * When the last phase of a band is done, it is marked so (DONE). | ||
| 357 | * Clearly, these phases must be properly ordered WRT each other. | ||
| 358 | */ | ||
| 359 | abstract class Band { | ||
| 360 | private int phase = NO_PHASE; | ||
| 361 | private final String name; | ||
| 362 | |||
| 363 | private int valuesExpected; | ||
| 364 | |||
| 365 | protected long outputSize = -1; // cache | ||
| 366 | |||
| 367 | final public Coding regularCoding; | ||
| 368 | |||
| 369 | final public int seqForDebug; | ||
| 370 | public int elementCountForDebug; | ||
| 371 | |||
| 372 | |||
| 373 | protected Band(String name, Coding regularCoding) { | ||
| 374 | this.name = name; | ||
| 375 | this.regularCoding = regularCoding; | ||
| 376 | this.seqForDebug = ++nextSeqForDebug; | ||
| 377 | if (verbose > 2) | ||
| 378 | Utils.log.fine("Band "+seqForDebug+" is "+name); | ||
| 379 | // caller must call init | ||
| 380 | } | ||
| 381 | |||
| 382 | public Band init() { | ||
| 383 | // Cannot due this from the constructor, because constructor | ||
| 384 | // may wish to initialize some subclass variables. | ||
| 385 | // Set initial phase for reading or writing: | ||
| 386 | if (isReader) | ||
| 387 | readyToExpect(); | ||
| 388 | else | ||
| 389 | readyToCollect(); | ||
| 390 | return this; | ||
| 391 | } | ||
| 392 | |||
| 393 | // common operations | ||
| 394 | boolean isReader() { return isReader; } | ||
| 395 | int phase() { return phase; } | ||
| 396 | String name() { return name; } | ||
| 397 | |||
| 398 | /** Return -1 if data buffer not allocated, else max length. */ | ||
| 399 | public abstract int capacity(); | ||
| 400 | |||
| 401 | /** Allocate data buffer to specified length. */ | ||
| 402 | protected abstract void setCapacity(int cap); | ||
| 403 | |||
| 404 | /** Return current number of values in buffer, which must exist. */ | ||
| 405 | public abstract int length(); | ||
| 406 | |||
| 407 | protected abstract int valuesRemainingForDebug(); | ||
| 408 | |||
| 409 | public final int valuesExpected() { | ||
| 410 | return valuesExpected; | ||
| 411 | } | ||
| 412 | |||
| 413 | /** Write out bytes, encoding the values. */ | ||
| 414 | public final void writeTo(OutputStream out) throws IOException { | ||
| 415 | assert(assertReadyToWriteTo(this, out)); | ||
| 416 | setPhase(WRITE_PHASE); | ||
| 417 | // subclasses continue by writing their contents to output | ||
| 418 | writeDataTo(out); | ||
| 419 | doneWriting(); | ||
| 420 | } | ||
| 421 | |||
| 422 | abstract void chooseBandCodings() throws IOException; | ||
| 423 | |||
| 424 | public final long outputSize() { | ||
| 425 | if (outputSize >= 0) { | ||
| 426 | long size = outputSize; | ||
| 427 | assert(size == computeOutputSize()); | ||
| 428 | return size; | ||
| 429 | } | ||
| 430 | return computeOutputSize(); | ||
| 431 | } | ||
| 432 | |||
| 433 | protected abstract long computeOutputSize(); | ||
| 434 | |||
| 435 | abstract protected void writeDataTo(OutputStream out) throws IOException; | ||
| 436 | |||
| 437 | /** Expect a certain number of values. */ | ||
| 438 | void expectLength(int l) { | ||
| 439 | assert(assertPhase(this, EXPECT_PHASE)); | ||
| 440 | assert(valuesExpected == 0); // all at once | ||
| 441 | assert(l >= 0); | ||
| 442 | valuesExpected = l; | ||
| 443 | } | ||
| 444 | /** Expect more values. (Multiple calls accumulate.) */ | ||
| 445 | void expectMoreLength(int l) { | ||
| 446 | assert(assertPhase(this, EXPECT_PHASE)); | ||
| 447 | valuesExpected += l; | ||
| 448 | } | ||
| 449 | |||
| 450 | |||
| 451 | /// Phase change markers. | ||
| 452 | |||
| 453 | private void readyToCollect() { // called implicitly by constructor | ||
| 454 | setCapacity(1); | ||
| 455 | setPhase(COLLECT_PHASE); | ||
| 456 | } | ||
| 457 | protected void doneWriting() { | ||
| 458 | assert(assertPhase(this, WRITE_PHASE)); | ||
| 459 | setPhase(DONE_PHASE); | ||
| 460 | } | ||
| 461 | private void readyToExpect() { // called implicitly by constructor | ||
| 462 | setPhase(EXPECT_PHASE); | ||
| 463 | } | ||
| 464 | /** Read in bytes, decoding the values. */ | ||
| 465 | public final void readFrom(InputStream in) throws IOException { | ||
| 466 | assert(assertReadyToReadFrom(this, in)); | ||
| 467 | setCapacity(valuesExpected()); | ||
| 468 | setPhase(READ_PHASE); | ||
| 469 | // subclasses continue by reading their contents from input: | ||
| 470 | readDataFrom(in); | ||
| 471 | readyToDisburse(); | ||
| 472 | } | ||
| 473 | abstract protected void readDataFrom(InputStream in) throws IOException; | ||
| 474 | protected void readyToDisburse() { | ||
| 475 | if (verbose > 1) Utils.log.fine("readyToDisburse "+this); | ||
| 476 | setPhase(DISBURSE_PHASE); | ||
| 477 | } | ||
| 478 | public void doneDisbursing() { | ||
| 479 | assert(assertPhase(this, DISBURSE_PHASE)); | ||
| 480 | setPhase(DONE_PHASE); | ||
| 481 | } | ||
| 482 | public final void doneWithUnusedBand() { | ||
| 483 | if (isReader) { | ||
| 484 | assert(assertPhase(this, EXPECT_PHASE)); | ||
| 485 | assert(valuesExpected() == 0); | ||
| 486 | // Fast forward: | ||
| 487 | setPhase(READ_PHASE); | ||
| 488 | setPhase(DISBURSE_PHASE); | ||
| 489 | setPhase(DONE_PHASE); | ||
| 490 | } else { | ||
| 491 | setPhase(FROZEN_PHASE); | ||
| 492 | } | ||
| 493 | } | ||
| 494 | |||
| 495 | protected void setPhase(int newPhase) { | ||
| 496 | assert(assertPhaseChangeOK(this, phase, newPhase)); | ||
| 497 | this.phase = newPhase; | ||
| 498 | } | ||
| 499 | |||
| 500 | protected int lengthForDebug = -1; // DEBUG ONLY | ||
| 501 | public String toString() { // DEBUG ONLY | ||
| 502 | int length = (lengthForDebug != -1 ? lengthForDebug : length()); | ||
| 503 | String str = name; | ||
| 504 | if (length != 0) | ||
| 505 | str += "[" + length + "]"; | ||
| 506 | if (elementCountForDebug != 0) | ||
| 507 | str += "(" + elementCountForDebug + ")"; | ||
| 508 | return str; | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | class ValueBand extends Band { | ||
| 513 | private int[] values; // must be null in EXPECT phase | ||
| 514 | private int length; | ||
| 515 | private int valuesDisbursed; | ||
| 516 | |||
| 517 | private CodingMethod bandCoding; | ||
| 518 | private byte[] metaCoding; | ||
| 519 | |||
| 520 | protected ValueBand(String name, Coding regularCoding) { | ||
| 521 | super(name, regularCoding); | ||
| 522 | } | ||
| 523 | |||
| 524 | public int capacity() { | ||
| 525 | return values == null ? -1 : values.length; | ||
| 526 | } | ||
| 527 | |||
| 528 | /** Declare predicted or needed capacity. */ | ||
| 529 | protected void setCapacity(int cap) { | ||
| 530 | assert(length <= cap); | ||
| 531 | if (cap == -1) { values = null; return; } | ||
| 532 | values = realloc(values, cap); | ||
| 533 | } | ||
| 534 | |||
| 535 | public int length() { | ||
| 536 | return length; | ||
| 537 | } | ||
| 538 | protected int valuesRemainingForDebug() { | ||
| 539 | return length - valuesDisbursed; | ||
| 540 | } | ||
| 541 | protected int valueAtForDebug(int i) { | ||
| 542 | return values[i]; | ||
| 543 | } | ||
| 544 | |||
| 545 | void patchValue(int i, int value) { | ||
| 546 | // Only one use for this. | ||
| 547 | assert(this == archive_header_S); | ||
| 548 | assert(i == AH_ARCHIVE_SIZE_HI || i == AH_ARCHIVE_SIZE_LO); | ||
| 549 | assert(i < length); // must have already output a dummy | ||
| 550 | values[i] = value; | ||
| 551 | outputSize = -1; // decache | ||
| 552 | } | ||
| 553 | |||
| 554 | protected void initializeValues(int[] values) { | ||
| 555 | assert(assertCanChangeLength(this)); | ||
| 556 | assert(length == 0); | ||
| 557 | this.values = values; | ||
| 558 | this.length = values.length; | ||
| 559 | } | ||
| 560 | |||
| 561 | /** Collect one value, or store one decoded value. */ | ||
| 562 | protected void addValue(int x) { | ||
| 563 | assert(assertCanChangeLength(this)); | ||
| 564 | if (length == values.length) | ||
| 565 | setCapacity(length < 1000 ? length * 10 : length * 2); | ||
| 566 | values[length++] = x; | ||
| 567 | } | ||
| 568 | |||
| 569 | private boolean canVaryCoding() { | ||
| 570 | if (!optVaryCodings) return false; | ||
| 571 | if (length == 0) return false; | ||
| 572 | // Can't read band_headers w/o the archive header: | ||
| 573 | if (this == archive_header_0) return false; | ||
| 574 | if (this == archive_header_S) return false; | ||
| 575 | if (this == archive_header_1) return false; | ||
| 576 | // BYTE1 bands can't vary codings, but the others can. | ||
| 577 | // All that's needed for the initial escape is at least | ||
| 578 | // 256 negative values or more than 256 non-negative values | ||
| 579 | return (regularCoding.min() <= -256 || regularCoding.max() >= 256); | ||
| 580 | } | ||
| 581 | |||
| 582 | private boolean shouldVaryCoding() { | ||
| 583 | assert(canVaryCoding()); | ||
| 584 | if (effort < MAX_EFFORT && length < SHORT_BAND_HEURISTIC) | ||
| 585 | return false; | ||
| 586 | return true; | ||
| 587 | } | ||
| 588 | |||
| 589 | protected void chooseBandCodings() throws IOException { | ||
| 590 | boolean canVary = canVaryCoding(); | ||
| 591 | if (!canVary || !shouldVaryCoding()) { | ||
| 592 | if (regularCoding.canRepresent(values, 0, length)) { | ||
| 593 | bandCoding = regularCoding; | ||
| 594 | } else { | ||
| 595 | assert(canVary); | ||
| 596 | if (verbose > 1) | ||
| 597 | Utils.log.fine("regular coding fails in band "+name()); | ||
| 598 | bandCoding = UNSIGNED5; | ||
| 599 | } | ||
| 600 | outputSize = -1; | ||
| 601 | } else { | ||
| 602 | int[] sizes = {0,0}; | ||
| 603 | bandCoding = chooseCoding(values, 0, length, | ||
| 604 | regularCoding, name(), | ||
| 605 | sizes); | ||
| 606 | outputSize = sizes[CodingChooser.BYTE_SIZE]; | ||
| 607 | if (outputSize == 0) // CodingChooser failed to size it. | ||
| 608 | outputSize = -1; | ||
| 609 | } | ||
| 610 | |||
| 611 | // Compute and save the meta-coding bytes also. | ||
| 612 | if (bandCoding != regularCoding) { | ||
| 613 | metaCoding = bandCoding.getMetaCoding(regularCoding); | ||
| 614 | if (verbose > 1) { | ||
| 615 | Utils.log.fine("alternate coding "+this+" "+bandCoding); | ||
| 616 | } | ||
| 617 | } else if (canVary && | ||
| 618 | decodeEscapeValue(values[0], regularCoding) >= 0) { | ||
| 619 | // Need an explicit default. | ||
| 620 | metaCoding = defaultMetaCoding; | ||
| 621 | } else { | ||
| 622 | // Common case: Zero bytes of meta coding. | ||
| 623 | metaCoding = noMetaCoding; | ||
| 624 | } | ||
| 625 | if (metaCoding.length > 0 | ||
| 626 | && (verbose > 2 || verbose > 1 && metaCoding.length > 1)) { | ||
| 627 | StringBuffer sb = new StringBuffer(); | ||
| 628 | for (int i = 0; i < metaCoding.length; i++) { | ||
| 629 | if (i == 1) sb.append(" /"); | ||
| 630 | sb.append(" ").append(metaCoding[i] & 0xFF); | ||
| 631 | } | ||
| 632 | Utils.log.fine(" meta-coding "+sb); | ||
| 633 | } | ||
| 634 | |||
| 635 | assert((outputSize < 0) || | ||
| 636 | !(bandCoding instanceof Coding) || | ||
| 637 | (outputSize == ((Coding)bandCoding) | ||
| 638 | .getLength(values, 0, length))) | ||
| 639 | : (bandCoding+" : "+ | ||
| 640 | outputSize+" != "+ | ||
| 641 | ((Coding)bandCoding).getLength(values, 0, length) | ||
| 642 | +" ?= "+getCodingChooser().computeByteSize(bandCoding,values,0,length) | ||
| 643 | ); | ||
| 644 | |||
| 645 | // Compute outputSize of the escape value X, if any. | ||
| 646 | if (metaCoding.length > 0) { | ||
| 647 | // First byte XB of meta-coding is treated specially, | ||
| 648 | // but any other bytes go into the band headers band. | ||
| 649 | // This must be done before any other output happens. | ||
| 650 | if (outputSize >= 0) | ||
| 651 | outputSize += computeEscapeSize(); // good cache | ||
| 652 | // Other bytes go into band_headers. | ||
| 653 | for (int i = 1; i < metaCoding.length; i++) { | ||
| 654 | band_headers.putByte(metaCoding[i] & 0xFF); | ||
| 655 | } | ||
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 659 | protected long computeOutputSize() { | ||
| 660 | outputSize = getCodingChooser().computeByteSize(bandCoding, | ||
| 661 | values, 0, length); | ||
| 662 | assert(outputSize < Integer.MAX_VALUE); | ||
| 663 | outputSize += computeEscapeSize(); | ||
| 664 | return outputSize; | ||
| 665 | } | ||
| 666 | |||
| 667 | protected int computeEscapeSize() { | ||
| 668 | if (metaCoding.length == 0) return 0; | ||
| 669 | int XB = metaCoding[0] & 0xFF; | ||
| 670 | int X = encodeEscapeValue(XB, regularCoding); | ||
| 671 | return regularCoding.setD(0).getLength(X); | ||
| 672 | } | ||
| 673 | |||
| 674 | protected void writeDataTo(OutputStream out) throws IOException { | ||
| 675 | if (length == 0) return; // nothing to write | ||
| 676 | long len0 = 0; | ||
| 677 | if (out == outputCounter) { | ||
| 678 | len0 = outputCounter.getCount(); | ||
| 679 | } | ||
| 680 | if (metaCoding.length > 0) { | ||
| 681 | int XB = metaCoding[0] & 0xFF; | ||
| 682 | // We need an explicit band header, either because | ||
| 683 | // there is a non-default coding method, or because | ||
| 684 | // the first value would be parsed as an escape value. | ||
| 685 | int X = encodeEscapeValue(XB, regularCoding); | ||
| 686 | //System.out.println("X="+X+" XB="+XB+" in "+this); | ||
| 687 | regularCoding.setD(0).writeTo(out, X); | ||
| 688 | } | ||
| 689 | bandCoding.writeArrayTo(out, values, 0, length); | ||
| 690 | if (out == outputCounter) { | ||
| 691 | assert(outputSize == outputCounter.getCount() - len0) | ||
| 692 | : (outputSize+" != "+outputCounter.getCount()+"-"+len0); | ||
| 693 | } | ||
| 694 | if (optDumpBands) dumpBand(); | ||
| 695 | } | ||
| 696 | |||
| 697 | protected void readDataFrom(InputStream in) throws IOException { | ||
| 698 | length = valuesExpected(); | ||
| 699 | if (length == 0) return; // nothing to read | ||
| 700 | if (verbose > 1) | ||
| 701 | Utils.log.fine("Reading band "+this); | ||
| 702 | if (!canVaryCoding()) { | ||
| 703 | bandCoding = regularCoding; | ||
| 704 | metaCoding = noMetaCoding; | ||
| 705 | } else { | ||
| 706 | assert(in.markSupported()); // input must be buffered | ||
| 707 | in.mark(Coding.B_MAX); | ||
| 708 | int X = regularCoding.setD(0).readFrom(in); | ||
| 709 | int XB = decodeEscapeValue(X, regularCoding); | ||
| 710 | if (XB < 0) { | ||
| 711 | // Do not consume this value. No alternate coding. | ||
| 712 | in.reset(); | ||
| 713 | XB = _meta_default; | ||
| 714 | bandCoding = regularCoding; | ||
| 715 | metaCoding = noMetaCoding; | ||
| 716 | } else if (XB == _meta_default) { | ||
| 717 | bandCoding = regularCoding; | ||
| 718 | metaCoding = defaultMetaCoding; | ||
| 719 | } else { | ||
| 720 | if (verbose > 2) | ||
| 721 | Utils.log.fine("found X="+X+" => XB="+XB); | ||
| 722 | bandCoding = getBandHeader(XB, regularCoding); | ||
| 723 | // This is really used only by dumpBands. | ||
| 724 | int p0 = bandHeaderBytePos0; | ||
| 725 | int p1 = bandHeaderBytePos; | ||
| 726 | metaCoding = new byte[p1-p0]; | ||
| 727 | System.arraycopy(bandHeaderBytes, p0, | ||
| 728 | metaCoding, 0, metaCoding.length); | ||
| 729 | } | ||
| 730 | } | ||
| 731 | if (bandCoding != regularCoding) { | ||
| 732 | if (verbose > 1) | ||
| 733 | Utils.log.fine(name()+": irregular coding "+bandCoding); | ||
| 734 | } | ||
| 735 | bandCoding.readArrayFrom(in, values, 0, length); | ||
| 736 | if (optDumpBands) dumpBand(); | ||
| 737 | } | ||
| 738 | |||
| 739 | public void doneDisbursing() { | ||
| 740 | super.doneDisbursing(); | ||
| 741 | values = null; // for GC | ||
| 742 | } | ||
| 743 | |||
| 744 | private void dumpBand() throws IOException { | ||
| 745 | assert(optDumpBands); | ||
| 746 | try (PrintStream ps = new PrintStream(getDumpStream(this, ".txt"))) { | ||
| 747 | String irr = (bandCoding == regularCoding) ? "" : " irregular"; | ||
| 748 | ps.print("# length="+length+ | ||
| 749 | " size="+outputSize()+ | ||
| 750 | irr+" coding="+bandCoding); | ||
| 751 | if (metaCoding != noMetaCoding) { | ||
| 752 | StringBuffer sb = new StringBuffer(); | ||
| 753 | for (int i = 0; i < metaCoding.length; i++) { | ||
| 754 | if (i == 1) sb.append(" /"); | ||
| 755 | sb.append(" ").append(metaCoding[i] & 0xFF); | ||
| 756 | } | ||
| 757 | ps.print(" //header: "+sb); | ||
| 758 | } | ||
| 759 | printArrayTo(ps, values, 0, length); | ||
| 760 | } | ||
| 761 | try (OutputStream ds = getDumpStream(this, ".bnd")) { | ||
| 762 | bandCoding.writeArrayTo(ds, values, 0, length); | ||
| 763 | } | ||
| 764 | } | ||
| 765 | |||
| 766 | /** Disburse one value. */ | ||
| 767 | protected int getValue() { | ||
| 768 | assert(phase() == DISBURSE_PHASE); | ||
| 769 | assert(valuesDisbursed < length); | ||
| 770 | return values[valuesDisbursed++]; | ||
| 771 | } | ||
| 772 | |||
| 773 | /** Reset for another pass over the same value set. */ | ||
| 774 | public void resetForSecondPass() { | ||
| 775 | assert(phase() == DISBURSE_PHASE); | ||
| 776 | assert(valuesDisbursed == length()); // 1st pass is complete | ||
| 777 | valuesDisbursed = 0; | ||
| 778 | } | ||
| 779 | } | ||
| 780 | |||
| 781 | class ByteBand extends Band { | ||
| 782 | private ByteArrayOutputStream bytes; // input buffer | ||
| 783 | private ByteArrayOutputStream bytesForDump; | ||
| 784 | private InputStream in; | ||
| 785 | |||
| 786 | public ByteBand(String name) { | ||
| 787 | super(name, BYTE1); | ||
| 788 | } | ||
| 789 | |||
| 790 | public int capacity() { | ||
| 791 | return bytes == null ? -1 : Integer.MAX_VALUE; | ||
| 792 | } | ||
| 793 | protected void setCapacity(int cap) { | ||
| 794 | assert(bytes == null); // do this just once | ||
| 795 | bytes = new ByteArrayOutputStream(cap); | ||
| 796 | } | ||
| 797 | public void destroy() { | ||
| 798 | lengthForDebug = length(); | ||
| 799 | bytes = null; | ||
| 800 | } | ||
| 801 | |||
| 802 | public int length() { | ||
| 803 | return bytes == null ? -1 : bytes.size(); | ||
| 804 | } | ||
| 805 | public void reset() { | ||
| 806 | bytes.reset(); | ||
| 807 | } | ||
| 808 | protected int valuesRemainingForDebug() { | ||
| 809 | return (bytes == null) ? -1 : ((ByteArrayInputStream)in).available(); | ||
| 810 | } | ||
| 811 | |||
| 812 | protected void chooseBandCodings() throws IOException { | ||
| 813 | // No-op. | ||
| 814 | assert(decodeEscapeValue(regularCoding.min(), regularCoding) < 0); | ||
| 815 | assert(decodeEscapeValue(regularCoding.max(), regularCoding) < 0); | ||
| 816 | } | ||
| 817 | |||
| 818 | protected long computeOutputSize() { | ||
| 819 | // do not cache | ||
| 820 | return bytes.size(); | ||
| 821 | } | ||
| 822 | |||
| 823 | public void writeDataTo(OutputStream out) throws IOException { | ||
| 824 | if (length() == 0) return; | ||
| 825 | bytes.writeTo(out); | ||
| 826 | if (optDumpBands) dumpBand(); | ||
| 827 | destroy(); // done with the bits! | ||
| 828 | } | ||
| 829 | |||
| 830 | private void dumpBand() throws IOException { | ||
| 831 | assert(optDumpBands); | ||
| 832 | try (OutputStream ds = getDumpStream(this, ".bnd")) { | ||
| 833 | if (bytesForDump != null) | ||
| 834 | bytesForDump.writeTo(ds); | ||
| 835 | else | ||
| 836 | bytes.writeTo(ds); | ||
| 837 | } | ||
| 838 | } | ||
| 839 | |||
| 840 | public void readDataFrom(InputStream in) throws IOException { | ||
| 841 | int vex = valuesExpected(); | ||
| 842 | if (vex == 0) return; | ||
| 843 | if (verbose > 1) { | ||
| 844 | lengthForDebug = vex; | ||
| 845 | Utils.log.fine("Reading band "+this); | ||
| 846 | lengthForDebug = -1; | ||
| 847 | } | ||
| 848 | byte[] buf = new byte[Math.min(vex, 1<<14)]; | ||
| 849 | while (vex > 0) { | ||
| 850 | int nr = in.read(buf, 0, Math.min(vex, buf.length)); | ||
| 851 | if (nr < 0) throw new EOFException(); | ||
| 852 | bytes.write(buf, 0, nr); | ||
| 853 | vex -= nr; | ||
| 854 | } | ||
| 855 | if (optDumpBands) dumpBand(); | ||
| 856 | } | ||
| 857 | |||
| 858 | public void readyToDisburse() { | ||
| 859 | in = new ByteArrayInputStream(bytes.toByteArray()); | ||
| 860 | super.readyToDisburse(); | ||
| 861 | } | ||
| 862 | |||
| 863 | public void doneDisbursing() { | ||
| 864 | super.doneDisbursing(); | ||
| 865 | if (optDumpBands | ||
| 866 | && bytesForDump != null && bytesForDump.size() > 0) { | ||
| 867 | try { | ||
| 868 | dumpBand(); | ||
| 869 | } catch (IOException ee) { | ||
| 870 | throw new RuntimeException(ee); | ||
| 871 | } | ||
| 872 | } | ||
| 873 | in = null; // GC | ||
| 874 | bytes = null; // GC | ||
| 875 | bytesForDump = null; // GC | ||
| 876 | } | ||
| 877 | |||
| 878 | // alternative to readFrom: | ||
| 879 | public void setInputStreamFrom(InputStream in) throws IOException { | ||
| 880 | assert(bytes == null); | ||
| 881 | assert(assertReadyToReadFrom(this, in)); | ||
| 882 | setPhase(READ_PHASE); | ||
| 883 | this.in = in; | ||
| 884 | if (optDumpBands) { | ||
| 885 | // Tap the stream. | ||
| 886 | bytesForDump = new ByteArrayOutputStream(); | ||
| 887 | this.in = new FilterInputStream(in) { | ||
| 888 | public int read() throws IOException { | ||
| 889 | int ch = in.read(); | ||
| 890 | if (ch >= 0) bytesForDump.write(ch); | ||
| 891 | return ch; | ||
| 892 | } | ||
| 893 | public int read(byte b[], int off, int len) throws IOException { | ||
| 894 | int nr = in.read(b, off, len); | ||
| 895 | if (nr >= 0) bytesForDump.write(b, off, nr); | ||
| 896 | return nr; | ||
| 897 | } | ||
| 898 | }; | ||
| 899 | } | ||
| 900 | super.readyToDisburse(); | ||
| 901 | } | ||
| 902 | |||
| 903 | public OutputStream collectorStream() { | ||
| 904 | assert(phase() == COLLECT_PHASE); | ||
| 905 | assert(bytes != null); | ||
| 906 | return bytes; | ||
| 907 | } | ||
| 908 | |||
| 909 | public InputStream getInputStream() { | ||
| 910 | assert(phase() == DISBURSE_PHASE); | ||
| 911 | assert(in != null); | ||
| 912 | return in; | ||
| 913 | } | ||
| 914 | public int getByte() throws IOException { | ||
| 915 | int b = getInputStream().read(); | ||
| 916 | if (b < 0) throw new EOFException(); | ||
| 917 | return b; | ||
| 918 | } | ||
| 919 | public void putByte(int b) throws IOException { | ||
| 920 | assert(b == (b & 0xFF)); | ||
| 921 | collectorStream().write(b); | ||
| 922 | } | ||
| 923 | public String toString() { | ||
| 924 | return "byte "+super.toString(); | ||
| 925 | } | ||
| 926 | } | ||
| 927 | |||
| 928 | class IntBand extends ValueBand { | ||
| 929 | // The usual coding for bands is 7bit/5byte/delta. | ||
| 930 | public IntBand(String name, Coding regularCoding) { | ||
| 931 | super(name, regularCoding); | ||
| 932 | } | ||
| 933 | |||
| 934 | public void putInt(int x) { | ||
| 935 | assert(phase() == COLLECT_PHASE); | ||
| 936 | addValue(x); | ||
| 937 | } | ||
| 938 | |||
| 939 | public int getInt() { | ||
| 940 | return getValue(); | ||
| 941 | } | ||
| 942 | /** Return the sum of all values in this band. */ | ||
| 943 | public int getIntTotal() { | ||
| 944 | assert(phase() == DISBURSE_PHASE); | ||
| 945 | // assert that this is the whole pass; no other reads allowed | ||
| 946 | assert(valuesRemainingForDebug() == length()); | ||
| 947 | int total = 0; | ||
| 948 | for (int k = length(); k > 0; k--) { | ||
| 949 | total += getInt(); | ||
| 950 | } | ||
| 951 | resetForSecondPass(); | ||
| 952 | return total; | ||
| 953 | } | ||
| 954 | /** Return the occurrence count of a specific value in this band. */ | ||
| 955 | public int getIntCount(int value) { | ||
| 956 | assert(phase() == DISBURSE_PHASE); | ||
| 957 | // assert that this is the whole pass; no other reads allowed | ||
| 958 | assert(valuesRemainingForDebug() == length()); | ||
| 959 | int total = 0; | ||
| 960 | for (int k = length(); k > 0; k--) { | ||
| 961 | if (getInt() == value) { | ||
| 962 | total += 1; | ||
| 963 | } | ||
| 964 | } | ||
| 965 | resetForSecondPass(); | ||
| 966 | return total; | ||
| 967 | } | ||
| 968 | } | ||
| 969 | |||
| 970 | static int getIntTotal(int[] values) { | ||
| 971 | int total = 0; | ||
| 972 | for (int i = 0; i < values.length; i++) { | ||
| 973 | total += values[i]; | ||
| 974 | } | ||
| 975 | return total; | ||
| 976 | } | ||
| 977 | |||
| 978 | class CPRefBand extends ValueBand { | ||
| 979 | Index index; | ||
| 980 | boolean nullOK; | ||
| 981 | |||
| 982 | public CPRefBand(String name, Coding regularCoding, byte cpTag, boolean nullOK) { | ||
| 983 | super(name, regularCoding); | ||
| 984 | this.nullOK = nullOK; | ||
| 985 | if (cpTag != CONSTANT_None) | ||
| 986 | setBandIndex(this, cpTag); | ||
| 987 | } | ||
| 988 | public CPRefBand(String name, Coding regularCoding, byte cpTag) { | ||
| 989 | this(name, regularCoding, cpTag, false); | ||
| 990 | } | ||
| 991 | public CPRefBand(String name, Coding regularCoding, Object undef) { | ||
| 992 | this(name, regularCoding, CONSTANT_None, false); | ||
| 993 | } | ||
| 994 | |||
| 995 | public void setIndex(Index index) { | ||
| 996 | this.index = index; | ||
| 997 | } | ||
| 998 | |||
| 999 | protected void readDataFrom(InputStream in) throws IOException { | ||
| 1000 | super.readDataFrom(in); | ||
| 1001 | assert(assertValidCPRefs(this)); | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | /** Write a constant pool reference. */ | ||
| 1005 | public void putRef(Entry e) { | ||
| 1006 | assert(index != null); | ||
| 1007 | addValue(encodeRefOrNull(e, index)); | ||
| 1008 | } | ||
| 1009 | public void putRef(Entry e, Index index) { | ||
| 1010 | assert(this.index == null); | ||
| 1011 | addValue(encodeRefOrNull(e, index)); | ||
| 1012 | } | ||
| 1013 | public void putRef(Entry e, byte cptag) { | ||
| 1014 | putRef(e, getCPIndex(cptag)); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | public Entry getRef() { | ||
| 1018 | if (index == null) Utils.log.warning("No index for "+this); | ||
| 1019 | assert(index != null); | ||
| 1020 | return decodeRefOrNull(getValue(), index); | ||
| 1021 | } | ||
| 1022 | public Entry getRef(Index index) { | ||
| 1023 | assert(this.index == null); | ||
| 1024 | return decodeRefOrNull(getValue(), index); | ||
| 1025 | } | ||
| 1026 | public Entry getRef(byte cptag) { | ||
| 1027 | return getRef(getCPIndex(cptag)); | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | private int encodeRefOrNull(Entry e, Index index) { | ||
| 1031 | int nonNullCode; // NNC is the coding which assumes nulls are rare | ||
| 1032 | if (e == null) { | ||
| 1033 | nonNullCode = -1; // negative values are rare | ||
| 1034 | } else { | ||
| 1035 | nonNullCode = encodeRef(e, index); | ||
| 1036 | } | ||
| 1037 | // If nulls are expected, increment, to make -1 code turn to 0. | ||
| 1038 | return (nullOK ? 1 : 0) + nonNullCode; | ||
| 1039 | } | ||
| 1040 | private Entry decodeRefOrNull(int code, Index index) { | ||
| 1041 | // Inverse to encodeRefOrNull... | ||
| 1042 | int nonNullCode = code - (nullOK ? 1 : 0); | ||
| 1043 | if (nonNullCode == -1) { | ||
| 1044 | return null; | ||
| 1045 | } else { | ||
| 1046 | return decodeRef(nonNullCode, index); | ||
| 1047 | } | ||
| 1048 | } | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | // Bootstrap support for CPRefBands. These are needed to record | ||
| 1052 | // intended CP indexes, before the CP has been created. | ||
| 1053 | private final List<CPRefBand> allKQBands = new ArrayList<>(); | ||
| 1054 | private List<Object[]> needPredefIndex = new ArrayList<>(); | ||
| 1055 | |||
| 1056 | |||
| 1057 | int encodeRef(Entry e, Index ix) { | ||
| 1058 | int coding = ix.indexOf(e); | ||
| 1059 | if (verbose > 2) | ||
| 1060 | Utils.log.fine("putRef "+coding+" => "+e); | ||
| 1061 | return coding; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | Entry decodeRef(int n, Index ix) { | ||
| 1065 | if (n < 0 || n >= ix.size()) | ||
| 1066 | Utils.log.warning("decoding bad ref "+n+" in "+ix); | ||
| 1067 | Entry e = ix.getEntry(n); | ||
| 1068 | if (verbose > 2) | ||
| 1069 | Utils.log.fine("getRef "+n+" => "+e); | ||
| 1070 | return e; | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | private CodingChooser codingChooser; | ||
| 1074 | protected CodingChooser getCodingChooser() { | ||
| 1075 | if (codingChooser == null) { | ||
| 1076 | codingChooser = new CodingChooser(effort, basicCodings); | ||
| 1077 | if (codingChooser.stress != null | ||
| 1078 | && this instanceof PackageWriter) { | ||
| 1079 | // Twist the random state based on my first file. | ||
| 1080 | // This sends each segment off in a different direction. | ||
| 1081 | List<Package.Class> classes = ((PackageWriter)this).pkg.classes; | ||
| 1082 | if (!classes.isEmpty()) { | ||
| 1083 | Package.Class cls = classes.get(0); | ||
| 1084 | codingChooser.addStressSeed(cls.getName().hashCode()); | ||
| 1085 | } | ||
| 1086 | } | ||
| 1087 | } | ||
| 1088 | return codingChooser; | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | public CodingMethod chooseCoding(int[] values, int start, int end, | ||
| 1092 | Coding regular, String bandName, | ||
| 1093 | int[] sizes) { | ||
| 1094 | assert(optVaryCodings); | ||
| 1095 | if (effort <= MIN_EFFORT) { | ||
| 1096 | return regular; | ||
| 1097 | } | ||
| 1098 | CodingChooser cc = getCodingChooser(); | ||
| 1099 | if (verbose > 1 || cc.verbose > 1) { | ||
| 1100 | Utils.log.fine("--- chooseCoding "+bandName); | ||
| 1101 | } | ||
| 1102 | return cc.choose(values, start, end, regular, sizes); | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | static final byte[] defaultMetaCoding = { _meta_default }; | ||
| 1106 | static final byte[] noMetaCoding = {}; | ||
| 1107 | |||
| 1108 | // The first value in a band is always coded with the default coding D. | ||
| 1109 | // If this first value X is an escape value, it actually represents the | ||
| 1110 | // first (and perhaps only) byte of a meta-coding. | ||
| 1111 | // | ||
| 1112 | // If D.S != 0 and D includes the range [-256..-1], | ||
| 1113 | // the escape values are in that range, | ||
| 1114 | // and the first byte XB is -1-X. | ||
| 1115 | // | ||
| 1116 | // If D.S == 0 and D includes the range [(D.L)..(D.L)+255], | ||
| 1117 | // the escape values are in that range, | ||
| 1118 | // and XB is X-(D.L). | ||
| 1119 | // | ||
| 1120 | // This representation is designed so that a band header is unlikely | ||
| 1121 | // to be confused with the initial value of a headerless band, | ||
| 1122 | // and yet so that a band header is likely to occupy only a byte or two. | ||
| 1123 | // | ||
| 1124 | // Result is in [0..255] if XB was successfully extracted, else -1. | ||
| 1125 | // See section "Coding Specifier Meta-Encoding" in the JSR 200 spec. | ||
| 1126 | protected static int decodeEscapeValue(int X, Coding regularCoding) { | ||
| 1127 | // The first value in a band is always coded with the default coding D. | ||
| 1128 | // If this first value X is an escape value, it actually represents the | ||
| 1129 | // first (and perhaps only) byte of a meta-coding. | ||
| 1130 | // Result is in [0..255] if XB was successfully extracted, else -1. | ||
| 1131 | if (regularCoding.B() == 1 || regularCoding.L() == 0) | ||
| 1132 | return -1; // degenerate regular coding (BYTE1) | ||
| 1133 | if (regularCoding.S() != 0) { | ||
| 1134 | if (-256 <= X && X <= -1 && regularCoding.min() <= -256) { | ||
| 1135 | int XB = -1-X; | ||
| 1136 | assert(XB >= 0 && XB < 256); | ||
| 1137 | return XB; | ||
| 1138 | } | ||
| 1139 | } else { | ||
| 1140 | int L = regularCoding.L(); | ||
| 1141 | if (L <= X && X <= L+255 && regularCoding.max() >= L+255) { | ||
| 1142 | int XB = X-L; | ||
| 1143 | assert(XB >= 0 && XB < 256); | ||
| 1144 | return XB; | ||
| 1145 | } | ||
| 1146 | } | ||
| 1147 | return -1; // negative value for failure | ||
| 1148 | } | ||
| 1149 | // Inverse to decodeEscapeValue(). | ||
| 1150 | protected static int encodeEscapeValue(int XB, Coding regularCoding) { | ||
| 1151 | assert(XB >= 0 && XB < 256); | ||
| 1152 | assert(regularCoding.B() > 1 && regularCoding.L() > 0); | ||
| 1153 | int X; | ||
| 1154 | if (regularCoding.S() != 0) { | ||
| 1155 | assert(regularCoding.min() <= -256); | ||
| 1156 | X = -1-XB; | ||
| 1157 | } else { | ||
| 1158 | int L = regularCoding.L(); | ||
| 1159 | assert(regularCoding.max() >= L+255); | ||
| 1160 | X = XB+L; | ||
| 1161 | } | ||
| 1162 | assert(decodeEscapeValue(X, regularCoding) == XB) | ||
| 1163 | : (regularCoding+" XB="+XB+" X="+X); | ||
| 1164 | return X; | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | static { | ||
| 1168 | boolean checkXB = false; | ||
| 1169 | assert(checkXB = true); | ||
| 1170 | if (checkXB) { | ||
| 1171 | for (int i = 0; i < basicCodings.length; i++) { | ||
| 1172 | Coding D = basicCodings[i]; | ||
| 1173 | if (D == null) continue; | ||
| 1174 | if (D.B() == 1) continue; | ||
| 1175 | if (D.L() == 0) continue; | ||
| 1176 | for (int XB = 0; XB <= 255; XB++) { | ||
| 1177 | // The following exercises decodeEscapeValue also: | ||
| 1178 | encodeEscapeValue(XB, D); | ||
| 1179 | } | ||
| 1180 | } | ||
| 1181 | } | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | class MultiBand extends Band { | ||
| 1185 | MultiBand(String name, Coding regularCoding) { | ||
| 1186 | super(name, regularCoding); | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | public Band init() { | ||
| 1190 | super.init(); | ||
| 1191 | // This is all just to keep the asserts happy: | ||
| 1192 | setCapacity(0); | ||
| 1193 | if (phase() == EXPECT_PHASE) { | ||
| 1194 | // Fast forward: | ||
| 1195 | setPhase(READ_PHASE); | ||
| 1196 | setPhase(DISBURSE_PHASE); | ||
| 1197 | } | ||
| 1198 | return this; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | Band[] bands = new Band[10]; | ||
| 1202 | int bandCount = 0; | ||
| 1203 | |||
| 1204 | int size() { | ||
| 1205 | return bandCount; | ||
| 1206 | } | ||
| 1207 | Band get(int i) { | ||
| 1208 | assert(i < bandCount); | ||
| 1209 | return bands[i]; | ||
| 1210 | } | ||
| 1211 | Band[] toArray() { | ||
| 1212 | return (Band[]) realloc(bands, bandCount); | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | void add(Band b) { | ||
| 1216 | assert(bandCount == 0 || notePrevForAssert(b, bands[bandCount-1])); | ||
| 1217 | if (bandCount == bands.length) { | ||
| 1218 | bands = (Band[]) realloc(bands); | ||
| 1219 | } | ||
| 1220 | bands[bandCount++] = b; | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | ByteBand newByteBand(String name) { | ||
| 1224 | ByteBand b = new ByteBand(name); | ||
| 1225 | b.init(); add(b); | ||
| 1226 | return b; | ||
| 1227 | } | ||
| 1228 | IntBand newIntBand(String name) { | ||
| 1229 | IntBand b = new IntBand(name, regularCoding); | ||
| 1230 | b.init(); add(b); | ||
| 1231 | return b; | ||
| 1232 | } | ||
| 1233 | IntBand newIntBand(String name, Coding regularCoding) { | ||
| 1234 | IntBand b = new IntBand(name, regularCoding); | ||
| 1235 | b.init(); add(b); | ||
| 1236 | return b; | ||
| 1237 | } | ||
| 1238 | MultiBand newMultiBand(String name, Coding regularCoding) { | ||
| 1239 | MultiBand b = new MultiBand(name, regularCoding); | ||
| 1240 | b.init(); add(b); | ||
| 1241 | return b; | ||
| 1242 | } | ||
| 1243 | CPRefBand newCPRefBand(String name, byte cpTag) { | ||
| 1244 | CPRefBand b = new CPRefBand(name, regularCoding, cpTag); | ||
| 1245 | b.init(); add(b); | ||
| 1246 | return b; | ||
| 1247 | } | ||
| 1248 | CPRefBand newCPRefBand(String name, Coding regularCoding, | ||
| 1249 | byte cpTag) { | ||
| 1250 | CPRefBand b = new CPRefBand(name, regularCoding, cpTag); | ||
| 1251 | b.init(); add(b); | ||
| 1252 | return b; | ||
| 1253 | } | ||
| 1254 | CPRefBand newCPRefBand(String name, Coding regularCoding, | ||
| 1255 | byte cpTag, boolean nullOK) { | ||
| 1256 | CPRefBand b = new CPRefBand(name, regularCoding, cpTag, nullOK); | ||
| 1257 | b.init(); add(b); | ||
| 1258 | return b; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | int bandCount() { return bandCount; } | ||
| 1262 | |||
| 1263 | private int cap = -1; | ||
| 1264 | public int capacity() { return cap; } | ||
| 1265 | public void setCapacity(int cap) { this.cap = cap; } | ||
| 1266 | |||
| 1267 | public int length() { return 0; } | ||
| 1268 | public int valuesRemainingForDebug() { return 0; } | ||
| 1269 | |||
| 1270 | protected void chooseBandCodings() throws IOException { | ||
| 1271 | // coding decision pass | ||
| 1272 | for (int i = 0; i < bandCount; i++) { | ||
| 1273 | Band b = bands[i]; | ||
| 1274 | b.chooseBandCodings(); | ||
| 1275 | } | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | protected long computeOutputSize() { | ||
| 1279 | // coding decision pass | ||
| 1280 | long sum = 0; | ||
| 1281 | for (int i = 0; i < bandCount; i++) { | ||
| 1282 | Band b = bands[i]; | ||
| 1283 | long bsize = b.outputSize(); | ||
| 1284 | assert(bsize >= 0) : b; | ||
| 1285 | sum += bsize; | ||
| 1286 | } | ||
| 1287 | // do not cache | ||
| 1288 | return sum; | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | protected void writeDataTo(OutputStream out) throws IOException { | ||
| 1292 | long preCount = 0; | ||
| 1293 | if (outputCounter != null) preCount = outputCounter.getCount(); | ||
| 1294 | for (int i = 0; i < bandCount; i++) { | ||
| 1295 | Band b = bands[i]; | ||
| 1296 | b.writeTo(out); | ||
| 1297 | if (outputCounter != null) { | ||
| 1298 | long postCount = outputCounter.getCount(); | ||
| 1299 | long len = postCount - preCount; | ||
| 1300 | preCount = postCount; | ||
| 1301 | if ((verbose > 0 && len > 0) || verbose > 1) { | ||
| 1302 | Utils.log.info(" ...wrote "+len+" bytes from "+b); | ||
| 1303 | } | ||
| 1304 | } | ||
| 1305 | } | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | protected void readDataFrom(InputStream in) throws IOException { | ||
| 1309 | assert(false); // not called? | ||
| 1310 | for (int i = 0; i < bandCount; i++) { | ||
| 1311 | Band b = bands[i]; | ||
| 1312 | b.readFrom(in); | ||
| 1313 | if ((verbose > 0 && b.length() > 0) || verbose > 1) { | ||
| 1314 | Utils.log.info(" ...read "+b); | ||
| 1315 | } | ||
| 1316 | } | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | public String toString() { | ||
| 1320 | return "{"+bandCount()+" bands: "+super.toString()+"}"; | ||
| 1321 | } | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | /** | ||
| 1325 | * An output stream which counts the number of bytes written. | ||
| 1326 | */ | ||
| 1327 | private static | ||
| 1328 | class ByteCounter extends FilterOutputStream { | ||
| 1329 | // (should go public under the name CountingOutputStream?) | ||
| 1330 | |||
| 1331 | private long count; | ||
| 1332 | |||
| 1333 | public ByteCounter(OutputStream out) { | ||
| 1334 | super(out); | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | public long getCount() { return count; } | ||
| 1338 | public void setCount(long c) { count = c; } | ||
| 1339 | |||
| 1340 | public void write(int b) throws IOException { | ||
| 1341 | count++; | ||
| 1342 | if (out != null) out.write(b); | ||
| 1343 | } | ||
| 1344 | public void write(byte b[], int off, int len) throws IOException { | ||
| 1345 | count += len; | ||
| 1346 | if (out != null) out.write(b, off, len); | ||
| 1347 | } | ||
| 1348 | public String toString() { | ||
| 1349 | return String.valueOf(getCount()); | ||
| 1350 | } | ||
| 1351 | } | ||
| 1352 | ByteCounter outputCounter; | ||
| 1353 | |||
| 1354 | void writeAllBandsTo(OutputStream out) throws IOException { | ||
| 1355 | // Wrap a byte-counter around the output stream. | ||
| 1356 | outputCounter = new ByteCounter(out); | ||
| 1357 | out = outputCounter; | ||
| 1358 | all_bands.writeTo(out); | ||
| 1359 | if (verbose > 0) { | ||
| 1360 | long nbytes = outputCounter.getCount(); | ||
| 1361 | Utils.log.info("Wrote total of "+nbytes+" bytes."); | ||
| 1362 | assert(nbytes == archiveSize0+archiveSize1); | ||
| 1363 | } | ||
| 1364 | outputCounter = null; | ||
| 1365 | } | ||
| 1366 | |||
| 1367 | // random AO_XXX bits, decoded from the archive header | ||
| 1368 | protected int archiveOptions; | ||
| 1369 | |||
| 1370 | // archiveSize1 sizes most of the archive [archive_options..file_bits). | ||
| 1371 | protected long archiveSize0; // size through archive_size_lo | ||
| 1372 | protected long archiveSize1; // size reported in archive_header | ||
| 1373 | protected int archiveNextCount; // reported in archive_header | ||
| 1374 | |||
| 1375 | static final int AH_LENGTH_0 = 3; //minver, majver, options | ||
| 1376 | static final int AH_ARCHIVE_SIZE_HI = 0; | ||
| 1377 | static final int AH_ARCHIVE_SIZE_LO = 1; | ||
| 1378 | static final int AH_LENGTH_S = 2; //optional size hi/lo | ||
| 1379 | static final int AH_LENGTH = 26; // mentioned in spec | ||
| 1380 | // Length contributions from optional header fields: | ||
| 1381 | static final int AH_FILE_HEADER_LEN = 5; // sizehi/lo/next/modtime/files | ||
| 1382 | static final int AH_SPECIAL_FORMAT_LEN = 2; // layouts/band-headers | ||
| 1383 | static final int AH_CP_NUMBER_LEN = 4; // int/float/long/double | ||
| 1384 | static final int AH_LENGTH_MIN = AH_LENGTH | ||
| 1385 | -(AH_SPECIAL_FORMAT_LEN+AH_FILE_HEADER_LEN+AH_CP_NUMBER_LEN); | ||
| 1386 | |||
| 1387 | // Common structure of attribute band groups: | ||
| 1388 | static final int AB_FLAGS_HI = 0; | ||
| 1389 | static final int AB_FLAGS_LO = 1; | ||
| 1390 | static final int AB_ATTR_COUNT = 2; | ||
| 1391 | static final int AB_ATTR_INDEXES = 3; | ||
| 1392 | static final int AB_ATTR_CALLS = 4; | ||
| 1393 | |||
| 1394 | static IntBand getAttrBand(MultiBand xxx_attr_bands, int which) { | ||
| 1395 | IntBand b = (IntBand) xxx_attr_bands.get(which); | ||
| 1396 | switch (which) { | ||
| 1397 | case AB_FLAGS_HI: | ||
| 1398 | assert(b.name().endsWith("_flags_hi")); break; | ||
| 1399 | case AB_FLAGS_LO: | ||
| 1400 | assert(b.name().endsWith("_flags_lo")); break; | ||
| 1401 | case AB_ATTR_COUNT: | ||
| 1402 | assert(b.name().endsWith("_attr_count")); break; | ||
| 1403 | case AB_ATTR_INDEXES: | ||
| 1404 | assert(b.name().endsWith("_attr_indexes")); break; | ||
| 1405 | case AB_ATTR_CALLS: | ||
| 1406 | assert(b.name().endsWith("_attr_calls")); break; | ||
| 1407 | default: | ||
| 1408 | assert(false); break; | ||
| 1409 | } | ||
| 1410 | return b; | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | static private final boolean NULL_IS_OK = true; | ||
| 1414 | |||
| 1415 | MultiBand all_bands = (MultiBand) new MultiBand("(package)", UNSIGNED5).init(); | ||
| 1416 | |||
| 1417 | // file header (various random bytes) | ||
| 1418 | ByteBand archive_magic = all_bands.newByteBand("archive_magic"); | ||
| 1419 | IntBand archive_header_0 = all_bands.newIntBand("archive_header_0", UNSIGNED5); | ||
| 1420 | IntBand archive_header_S = all_bands.newIntBand("archive_header_S", UNSIGNED5); | ||
| 1421 | IntBand archive_header_1 = all_bands.newIntBand("archive_header_1", UNSIGNED5); | ||
| 1422 | ByteBand band_headers = all_bands.newByteBand("band_headers"); | ||
| 1423 | |||
| 1424 | // constant pool contents | ||
| 1425 | MultiBand cp_bands = all_bands.newMultiBand("(constant_pool)", DELTA5); | ||
| 1426 | IntBand cp_Utf8_prefix = cp_bands.newIntBand("cp_Utf8_prefix"); | ||
| 1427 | IntBand cp_Utf8_suffix = cp_bands.newIntBand("cp_Utf8_suffix", UNSIGNED5); | ||
| 1428 | IntBand cp_Utf8_chars = cp_bands.newIntBand("cp_Utf8_chars", CHAR3); | ||
| 1429 | IntBand cp_Utf8_big_suffix = cp_bands.newIntBand("cp_Utf8_big_suffix"); | ||
| 1430 | MultiBand cp_Utf8_big_chars = cp_bands.newMultiBand("(cp_Utf8_big_chars)", DELTA5); | ||
| 1431 | IntBand cp_Int = cp_bands.newIntBand("cp_Int", UDELTA5); | ||
| 1432 | IntBand cp_Float = cp_bands.newIntBand("cp_Float", UDELTA5); | ||
| 1433 | IntBand cp_Long_hi = cp_bands.newIntBand("cp_Long_hi", UDELTA5); | ||
| 1434 | IntBand cp_Long_lo = cp_bands.newIntBand("cp_Long_lo"); | ||
| 1435 | IntBand cp_Double_hi = cp_bands.newIntBand("cp_Double_hi", UDELTA5); | ||
| 1436 | IntBand cp_Double_lo = cp_bands.newIntBand("cp_Double_lo"); | ||
| 1437 | CPRefBand cp_String = cp_bands.newCPRefBand("cp_String", UDELTA5, CONSTANT_Utf8); | ||
| 1438 | CPRefBand cp_Class = cp_bands.newCPRefBand("cp_Class", UDELTA5, CONSTANT_Utf8); | ||
| 1439 | CPRefBand cp_Signature_form = cp_bands.newCPRefBand("cp_Signature_form", CONSTANT_Utf8); | ||
| 1440 | CPRefBand cp_Signature_classes = cp_bands.newCPRefBand("cp_Signature_classes", UDELTA5, CONSTANT_Class); | ||
| 1441 | CPRefBand cp_Descr_name = cp_bands.newCPRefBand("cp_Descr_name", CONSTANT_Utf8); | ||
| 1442 | CPRefBand cp_Descr_type = cp_bands.newCPRefBand("cp_Descr_type", UDELTA5, CONSTANT_Signature); | ||
| 1443 | CPRefBand cp_Field_class = cp_bands.newCPRefBand("cp_Field_class", CONSTANT_Class); | ||
| 1444 | CPRefBand cp_Field_desc = cp_bands.newCPRefBand("cp_Field_desc", UDELTA5, CONSTANT_NameandType); | ||
| 1445 | CPRefBand cp_Method_class = cp_bands.newCPRefBand("cp_Method_class", CONSTANT_Class); | ||
| 1446 | CPRefBand cp_Method_desc = cp_bands.newCPRefBand("cp_Method_desc", UDELTA5, CONSTANT_NameandType); | ||
| 1447 | CPRefBand cp_Imethod_class = cp_bands.newCPRefBand("cp_Imethod_class", CONSTANT_Class); | ||
| 1448 | CPRefBand cp_Imethod_desc = cp_bands.newCPRefBand("cp_Imethod_desc", UDELTA5, CONSTANT_NameandType); | ||
| 1449 | |||
| 1450 | // bands for carrying attribute definitions: | ||
| 1451 | MultiBand attr_definition_bands = all_bands.newMultiBand("(attr_definition_bands)", UNSIGNED5); | ||
| 1452 | ByteBand attr_definition_headers = attr_definition_bands.newByteBand("attr_definition_headers"); | ||
| 1453 | CPRefBand attr_definition_name = attr_definition_bands.newCPRefBand("attr_definition_name", CONSTANT_Utf8); | ||
| 1454 | CPRefBand attr_definition_layout = attr_definition_bands.newCPRefBand("attr_definition_layout", CONSTANT_Utf8); | ||
| 1455 | |||
| 1456 | // bands for hardwired InnerClasses attribute (shared across the package) | ||
| 1457 | MultiBand ic_bands = all_bands.newMultiBand("(ic_bands)", DELTA5); | ||
| 1458 | CPRefBand ic_this_class = ic_bands.newCPRefBand("ic_this_class", UDELTA5, CONSTANT_Class); | ||
| 1459 | IntBand ic_flags = ic_bands.newIntBand("ic_flags", UNSIGNED5); | ||
| 1460 | // These bands contain data only where flags sets ACC_IC_LONG_FORM: | ||
| 1461 | CPRefBand ic_outer_class = ic_bands.newCPRefBand("ic_outer_class", DELTA5, CONSTANT_Class, NULL_IS_OK); | ||
| 1462 | CPRefBand ic_name = ic_bands.newCPRefBand("ic_name", DELTA5, CONSTANT_Utf8, NULL_IS_OK); | ||
| 1463 | |||
| 1464 | // bands for carrying class schema information: | ||
| 1465 | MultiBand class_bands = all_bands.newMultiBand("(class_bands)", DELTA5); | ||
| 1466 | CPRefBand class_this = class_bands.newCPRefBand("class_this", CONSTANT_Class); | ||
| 1467 | CPRefBand class_super = class_bands.newCPRefBand("class_super", CONSTANT_Class); | ||
| 1468 | IntBand class_interface_count = class_bands.newIntBand("class_interface_count"); | ||
| 1469 | CPRefBand class_interface = class_bands.newCPRefBand("class_interface", CONSTANT_Class); | ||
| 1470 | |||
| 1471 | // bands for class members | ||
| 1472 | IntBand class_field_count = class_bands.newIntBand("class_field_count"); | ||
| 1473 | IntBand class_method_count = class_bands.newIntBand("class_method_count"); | ||
| 1474 | |||
| 1475 | CPRefBand field_descr = class_bands.newCPRefBand("field_descr", CONSTANT_NameandType); | ||
| 1476 | MultiBand field_attr_bands = class_bands.newMultiBand("(field_attr_bands)", UNSIGNED5); | ||
| 1477 | IntBand field_flags_hi = field_attr_bands.newIntBand("field_flags_hi"); | ||
| 1478 | IntBand field_flags_lo = field_attr_bands.newIntBand("field_flags_lo"); | ||
| 1479 | IntBand field_attr_count = field_attr_bands.newIntBand("field_attr_count"); | ||
| 1480 | IntBand field_attr_indexes = field_attr_bands.newIntBand("field_attr_indexes"); | ||
| 1481 | IntBand field_attr_calls = field_attr_bands.newIntBand("field_attr_calls"); | ||
| 1482 | |||
| 1483 | // bands for predefined field attributes | ||
| 1484 | CPRefBand field_ConstantValue_KQ = field_attr_bands.newCPRefBand("field_ConstantValue_KQ", CONSTANT_Literal); | ||
| 1485 | CPRefBand field_Signature_RS = field_attr_bands.newCPRefBand("field_Signature_RS", CONSTANT_Signature); | ||
| 1486 | MultiBand field_metadata_bands = field_attr_bands.newMultiBand("(field_metadata_bands)", UNSIGNED5); | ||
| 1487 | |||
| 1488 | CPRefBand method_descr = class_bands.newCPRefBand("method_descr", MDELTA5, CONSTANT_NameandType); | ||
| 1489 | MultiBand method_attr_bands = class_bands.newMultiBand("(method_attr_bands)", UNSIGNED5); | ||
| 1490 | IntBand method_flags_hi = method_attr_bands.newIntBand("method_flags_hi"); | ||
| 1491 | IntBand method_flags_lo = method_attr_bands.newIntBand("method_flags_lo"); | ||
| 1492 | IntBand method_attr_count = method_attr_bands.newIntBand("method_attr_count"); | ||
| 1493 | IntBand method_attr_indexes = method_attr_bands.newIntBand("method_attr_indexes"); | ||
| 1494 | IntBand method_attr_calls = method_attr_bands.newIntBand("method_attr_calls"); | ||
| 1495 | // band for predefined method attributes | ||
| 1496 | IntBand method_Exceptions_N = method_attr_bands.newIntBand("method_Exceptions_N"); | ||
| 1497 | CPRefBand method_Exceptions_RC = method_attr_bands.newCPRefBand("method_Exceptions_RC", CONSTANT_Class); | ||
| 1498 | CPRefBand method_Signature_RS = method_attr_bands.newCPRefBand("method_Signature_RS", CONSTANT_Signature); | ||
| 1499 | MultiBand method_metadata_bands = method_attr_bands.newMultiBand("(method_metadata_bands)", UNSIGNED5); | ||
| 1500 | |||
| 1501 | MultiBand class_attr_bands = class_bands.newMultiBand("(class_attr_bands)", UNSIGNED5); | ||
| 1502 | IntBand class_flags_hi = class_attr_bands.newIntBand("class_flags_hi"); | ||
| 1503 | IntBand class_flags_lo = class_attr_bands.newIntBand("class_flags_lo"); | ||
| 1504 | IntBand class_attr_count = class_attr_bands.newIntBand("class_attr_count"); | ||
| 1505 | IntBand class_attr_indexes = class_attr_bands.newIntBand("class_attr_indexes"); | ||
| 1506 | IntBand class_attr_calls = class_attr_bands.newIntBand("class_attr_calls"); | ||
| 1507 | // band for predefined SourceFile and other class attributes | ||
| 1508 | CPRefBand class_SourceFile_RUN = class_attr_bands.newCPRefBand("class_SourceFile_RUN", UNSIGNED5, CONSTANT_Utf8, NULL_IS_OK); | ||
| 1509 | CPRefBand class_EnclosingMethod_RC = class_attr_bands.newCPRefBand("class_EnclosingMethod_RC", CONSTANT_Class); | ||
| 1510 | CPRefBand class_EnclosingMethod_RDN = class_attr_bands.newCPRefBand("class_EnclosingMethod_RDN", UNSIGNED5, CONSTANT_NameandType, NULL_IS_OK); | ||
| 1511 | CPRefBand class_Signature_RS = class_attr_bands.newCPRefBand("class_Signature_RS", CONSTANT_Signature); | ||
| 1512 | MultiBand class_metadata_bands = class_attr_bands.newMultiBand("(class_metadata_bands)", UNSIGNED5); | ||
| 1513 | IntBand class_InnerClasses_N = class_attr_bands.newIntBand("class_InnerClasses_N"); | ||
| 1514 | CPRefBand class_InnerClasses_RC = class_attr_bands.newCPRefBand("class_InnerClasses_RC", CONSTANT_Class); | ||
| 1515 | IntBand class_InnerClasses_F = class_attr_bands.newIntBand("class_InnerClasses_F"); | ||
| 1516 | CPRefBand class_InnerClasses_outer_RCN = class_attr_bands.newCPRefBand("class_InnerClasses_outer_RCN", UNSIGNED5, CONSTANT_Class, NULL_IS_OK); | ||
| 1517 | CPRefBand class_InnerClasses_name_RUN = class_attr_bands.newCPRefBand("class_InnerClasses_name_RUN", UNSIGNED5, CONSTANT_Utf8, NULL_IS_OK); | ||
| 1518 | IntBand class_ClassFile_version_minor_H = class_attr_bands.newIntBand("class_ClassFile_version_minor_H"); | ||
| 1519 | IntBand class_ClassFile_version_major_H = class_attr_bands.newIntBand("class_ClassFile_version_major_H"); | ||
| 1520 | |||
| 1521 | MultiBand code_bands = class_bands.newMultiBand("(code_bands)", UNSIGNED5); | ||
| 1522 | ByteBand code_headers = code_bands.newByteBand("code_headers"); //BYTE1 | ||
| 1523 | IntBand code_max_stack = code_bands.newIntBand("code_max_stack", UNSIGNED5); | ||
| 1524 | IntBand code_max_na_locals = code_bands.newIntBand("code_max_na_locals", UNSIGNED5); | ||
| 1525 | IntBand code_handler_count = code_bands.newIntBand("code_handler_count", UNSIGNED5); | ||
| 1526 | IntBand code_handler_start_P = code_bands.newIntBand("code_handler_start_P", BCI5); | ||
| 1527 | IntBand code_handler_end_PO = code_bands.newIntBand("code_handler_end_PO", BRANCH5); | ||
| 1528 | IntBand code_handler_catch_PO = code_bands.newIntBand("code_handler_catch_PO", BRANCH5); | ||
| 1529 | CPRefBand code_handler_class_RCN = code_bands.newCPRefBand("code_handler_class_RCN", UNSIGNED5, CONSTANT_Class, NULL_IS_OK); | ||
| 1530 | |||
| 1531 | MultiBand code_attr_bands = class_bands.newMultiBand("(code_attr_bands)", UNSIGNED5); | ||
| 1532 | IntBand code_flags_hi = code_attr_bands.newIntBand("code_flags_hi"); | ||
| 1533 | IntBand code_flags_lo = code_attr_bands.newIntBand("code_flags_lo"); | ||
| 1534 | IntBand code_attr_count = code_attr_bands.newIntBand("code_attr_count"); | ||
| 1535 | IntBand code_attr_indexes = code_attr_bands.newIntBand("code_attr_indexes"); | ||
| 1536 | IntBand code_attr_calls = code_attr_bands.newIntBand("code_attr_calls"); | ||
| 1537 | |||
| 1538 | MultiBand stackmap_bands = code_attr_bands.newMultiBand("StackMapTable_bands", UNSIGNED5); | ||
| 1539 | IntBand code_StackMapTable_N = stackmap_bands.newIntBand("code_StackMapTable_N"); | ||
| 1540 | IntBand code_StackMapTable_frame_T = stackmap_bands.newIntBand("code_StackMapTable_frame_T",BYTE1); | ||
| 1541 | IntBand code_StackMapTable_local_N = stackmap_bands.newIntBand("code_StackMapTable_local_N"); | ||
| 1542 | IntBand code_StackMapTable_stack_N = stackmap_bands.newIntBand("code_StackMapTable_stack_N"); | ||
| 1543 | IntBand code_StackMapTable_offset = stackmap_bands.newIntBand("code_StackMapTable_offset", UNSIGNED5); | ||
| 1544 | IntBand code_StackMapTable_T = stackmap_bands.newIntBand("code_StackMapTable_T", BYTE1); | ||
| 1545 | CPRefBand code_StackMapTable_RC = stackmap_bands.newCPRefBand("code_StackMapTable_RC", CONSTANT_Class); | ||
| 1546 | IntBand code_StackMapTable_P = stackmap_bands.newIntBand("code_StackMapTable_P", BCI5); | ||
| 1547 | |||
| 1548 | // bands for predefined LineNumberTable attribute | ||
| 1549 | IntBand code_LineNumberTable_N = code_attr_bands.newIntBand("code_LineNumberTable_N"); | ||
| 1550 | IntBand code_LineNumberTable_bci_P = code_attr_bands.newIntBand("code_LineNumberTable_bci_P", BCI5); | ||
| 1551 | IntBand code_LineNumberTable_line = code_attr_bands.newIntBand("code_LineNumberTable_line"); | ||
| 1552 | |||
| 1553 | // bands for predefined LocalVariable{Type}Table attributes | ||
| 1554 | IntBand code_LocalVariableTable_N = code_attr_bands.newIntBand("code_LocalVariableTable_N"); | ||
| 1555 | IntBand code_LocalVariableTable_bci_P = code_attr_bands.newIntBand("code_LocalVariableTable_bci_P", BCI5); | ||
| 1556 | IntBand code_LocalVariableTable_span_O = code_attr_bands.newIntBand("code_LocalVariableTable_span_O", BRANCH5); | ||
| 1557 | CPRefBand code_LocalVariableTable_name_RU = code_attr_bands.newCPRefBand("code_LocalVariableTable_name_RU", CONSTANT_Utf8); | ||
| 1558 | CPRefBand code_LocalVariableTable_type_RS = code_attr_bands.newCPRefBand("code_LocalVariableTable_type_RS", CONSTANT_Signature); | ||
| 1559 | IntBand code_LocalVariableTable_slot = code_attr_bands.newIntBand("code_LocalVariableTable_slot"); | ||
| 1560 | IntBand code_LocalVariableTypeTable_N = code_attr_bands.newIntBand("code_LocalVariableTypeTable_N"); | ||
| 1561 | IntBand code_LocalVariableTypeTable_bci_P = code_attr_bands.newIntBand("code_LocalVariableTypeTable_bci_P", BCI5); | ||
| 1562 | IntBand code_LocalVariableTypeTable_span_O = code_attr_bands.newIntBand("code_LocalVariableTypeTable_span_O", BRANCH5); | ||
| 1563 | CPRefBand code_LocalVariableTypeTable_name_RU = code_attr_bands.newCPRefBand("code_LocalVariableTypeTable_name_RU", CONSTANT_Utf8); | ||
| 1564 | CPRefBand code_LocalVariableTypeTable_type_RS = code_attr_bands.newCPRefBand("code_LocalVariableTypeTable_type_RS", CONSTANT_Signature); | ||
| 1565 | IntBand code_LocalVariableTypeTable_slot = code_attr_bands.newIntBand("code_LocalVariableTypeTable_slot"); | ||
| 1566 | |||
| 1567 | // bands for bytecodes | ||
| 1568 | MultiBand bc_bands = all_bands.newMultiBand("(byte_codes)", UNSIGNED5); | ||
| 1569 | ByteBand bc_codes = bc_bands.newByteBand("bc_codes"); //BYTE1 | ||
| 1570 | // remaining bands provide typed opcode fields required by the bc_codes | ||
| 1571 | |||
| 1572 | IntBand bc_case_count = bc_bands.newIntBand("bc_case_count"); // *switch | ||
| 1573 | IntBand bc_case_value = bc_bands.newIntBand("bc_case_value", DELTA5); // *switch | ||
| 1574 | ByteBand bc_byte = bc_bands.newByteBand("bc_byte"); //BYTE1 // bipush, iinc, *newarray | ||
| 1575 | IntBand bc_short = bc_bands.newIntBand("bc_short", DELTA5); // sipush, wide iinc | ||
| 1576 | IntBand bc_local = bc_bands.newIntBand("bc_local"); // *load, *store, iinc, ret | ||
| 1577 | IntBand bc_label = bc_bands.newIntBand("bc_label", BRANCH5); // if*, goto*, jsr*, *switch | ||
| 1578 | |||
| 1579 | // Most CP refs exhibit some correlation, and benefit from delta coding. | ||
| 1580 | // The notable exceptions are class and method references. | ||
| 1581 | |||
| 1582 | // ldc* operands: | ||
| 1583 | CPRefBand bc_intref = bc_bands.newCPRefBand("bc_intref", DELTA5, CONSTANT_Integer); | ||
| 1584 | CPRefBand bc_floatref = bc_bands.newCPRefBand("bc_floatref", DELTA5, CONSTANT_Float); | ||
| 1585 | CPRefBand bc_longref = bc_bands.newCPRefBand("bc_longref", DELTA5, CONSTANT_Long); | ||
| 1586 | CPRefBand bc_doubleref = bc_bands.newCPRefBand("bc_doubleref", DELTA5, CONSTANT_Double); | ||
| 1587 | CPRefBand bc_stringref = bc_bands.newCPRefBand("bc_stringref", DELTA5, CONSTANT_String); | ||
| 1588 | |||
| 1589 | // nulls produced by bc_classref are taken to mean the current class | ||
| 1590 | CPRefBand bc_classref = bc_bands.newCPRefBand("bc_classref", UNSIGNED5, CONSTANT_Class, NULL_IS_OK); // new, *anew*, c*cast, i*of, ldc | ||
| 1591 | CPRefBand bc_fieldref = bc_bands.newCPRefBand("bc_fieldref", DELTA5, CONSTANT_Fieldref); // get*, put* | ||
| 1592 | CPRefBand bc_methodref = bc_bands.newCPRefBand("bc_methodref", CONSTANT_Methodref); // invoke[vs]* | ||
| 1593 | CPRefBand bc_imethodref = bc_bands.newCPRefBand("bc_imethodref", DELTA5, CONSTANT_InterfaceMethodref); // invokeinterface | ||
| 1594 | |||
| 1595 | // _self_linker_op family | ||
| 1596 | CPRefBand bc_thisfield = bc_bands.newCPRefBand("bc_thisfield", CONSTANT_None); // any field within cur. class | ||
| 1597 | CPRefBand bc_superfield = bc_bands.newCPRefBand("bc_superfield", CONSTANT_None); // any field within superclass | ||
| 1598 | CPRefBand bc_thismethod = bc_bands.newCPRefBand("bc_thismethod", CONSTANT_None); // any method within cur. class | ||
| 1599 | CPRefBand bc_supermethod = bc_bands.newCPRefBand("bc_supermethod", CONSTANT_None); // any method within superclass | ||
| 1600 | // bc_invokeinit family: | ||
| 1601 | IntBand bc_initref = bc_bands.newIntBand("bc_initref"); | ||
| 1602 | // escapes | ||
| 1603 | CPRefBand bc_escref = bc_bands.newCPRefBand("bc_escref", CONSTANT_All); | ||
| 1604 | IntBand bc_escrefsize = bc_bands.newIntBand("bc_escrefsize"); | ||
| 1605 | IntBand bc_escsize = bc_bands.newIntBand("bc_escsize"); | ||
| 1606 | ByteBand bc_escbyte = bc_bands.newByteBand("bc_escbyte"); | ||
| 1607 | |||
| 1608 | // bands for carrying resource files and file attributes: | ||
| 1609 | MultiBand file_bands = all_bands.newMultiBand("(file_bands)", UNSIGNED5); | ||
| 1610 | CPRefBand file_name = file_bands.newCPRefBand("file_name", CONSTANT_Utf8); | ||
| 1611 | IntBand file_size_hi = file_bands.newIntBand("file_size_hi"); | ||
| 1612 | IntBand file_size_lo = file_bands.newIntBand("file_size_lo"); | ||
| 1613 | IntBand file_modtime = file_bands.newIntBand("file_modtime", DELTA5); | ||
| 1614 | IntBand file_options = file_bands.newIntBand("file_options"); | ||
| 1615 | ByteBand file_bits = file_bands.newByteBand("file_bits"); | ||
| 1616 | |||
| 1617 | // End of band definitions! | ||
| 1618 | |||
| 1619 | /** Given CP indexes, distribute tag-specific indexes to bands. */ | ||
| 1620 | protected void setBandIndexes() { | ||
| 1621 | // Handle prior calls to setBandIndex: | ||
| 1622 | for (Object[] need : needPredefIndex) { | ||
| 1623 | CPRefBand b = (CPRefBand) need[0]; | ||
| 1624 | Byte which = (Byte) need[1]; | ||
| 1625 | b.setIndex(getCPIndex(which.byteValue())); | ||
| 1626 | } | ||
| 1627 | needPredefIndex = null; // no more predefs | ||
| 1628 | |||
| 1629 | if (verbose > 3) { | ||
| 1630 | printCDecl(all_bands); | ||
| 1631 | } | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | protected void setBandIndex(CPRefBand b, byte which) { | ||
| 1635 | Object[] need = { b, Byte.valueOf(which) }; | ||
| 1636 | if (which == CONSTANT_Literal) { | ||
| 1637 | // I.e., attribute layouts KQ (no null) or KQN (null ok). | ||
| 1638 | allKQBands.add(b); | ||
| 1639 | } else if (needPredefIndex != null) { | ||
| 1640 | needPredefIndex.add(need); | ||
| 1641 | } else { | ||
| 1642 | // Not in predefinition mode; getCPIndex now works. | ||
| 1643 | b.setIndex(getCPIndex(which)); | ||
| 1644 | } | ||
| 1645 | } | ||
| 1646 | |||
| 1647 | protected void setConstantValueIndex(Field f) { | ||
| 1648 | Index ix = null; | ||
| 1649 | if (f != null) { | ||
| 1650 | byte tag = f.getLiteralTag(); | ||
| 1651 | ix = getCPIndex(tag); | ||
| 1652 | if (verbose > 2) | ||
| 1653 | Utils.log.fine("setConstantValueIndex "+f+" "+ConstantPool.tagName(tag)+" => "+ix); | ||
| 1654 | assert(ix != null); | ||
| 1655 | } | ||
| 1656 | // Typically, allKQBands is the singleton of field_ConstantValue_KQ. | ||
| 1657 | for (CPRefBand xxx_KQ : allKQBands) { | ||
| 1658 | xxx_KQ.setIndex(ix); | ||
| 1659 | } | ||
| 1660 | } | ||
| 1661 | |||
| 1662 | // Table of bands which contain metadata. | ||
| 1663 | protected MultiBand[] metadataBands = new MultiBand[ATTR_CONTEXT_LIMIT]; | ||
| 1664 | { | ||
| 1665 | metadataBands[ATTR_CONTEXT_CLASS] = class_metadata_bands; | ||
| 1666 | metadataBands[ATTR_CONTEXT_FIELD] = field_metadata_bands; | ||
| 1667 | metadataBands[ATTR_CONTEXT_METHOD] = method_metadata_bands; | ||
| 1668 | } | ||
| 1669 | |||
| 1670 | // Attribute layouts. | ||
| 1671 | public static final int ADH_CONTEXT_MASK = 0x3; // (ad_hdr & ADH_CONTEXT_MASK) | ||
| 1672 | public static final int ADH_BIT_SHIFT = 0x2; // (ad_hdr >> ADH_BIT_SHIFT) | ||
| 1673 | public static final int ADH_BIT_IS_LSB = 1; | ||
| 1674 | public static final int ATTR_INDEX_OVERFLOW = -1; | ||
| 1675 | |||
| 1676 | public int[] attrIndexLimit = new int[ATTR_CONTEXT_LIMIT]; | ||
| 1677 | // Each index limit is either 32 or 63, depending on AO_HAVE_XXX_FLAGS_HI. | ||
| 1678 | |||
| 1679 | // Which flag bits are taken over by attributes? | ||
| 1680 | protected long[] attrFlagMask = new long[ATTR_CONTEXT_LIMIT]; | ||
| 1681 | // Which flag bits have been taken over explicitly? | ||
| 1682 | protected long[] attrDefSeen = new long[ATTR_CONTEXT_LIMIT]; | ||
| 1683 | |||
| 1684 | // What pseudo-attribute bits are there to watch for? | ||
| 1685 | protected int[] attrOverflowMask = new int[ATTR_CONTEXT_LIMIT]; | ||
| 1686 | protected int attrClassFileVersionMask; | ||
| 1687 | |||
| 1688 | // Mapping from Attribute.Layout to Band[] (layout element bands). | ||
| 1689 | protected Map<Attribute.Layout, Band[]> attrBandTable = new HashMap<>(); | ||
| 1690 | |||
| 1691 | // Well-known attributes: | ||
| 1692 | protected final Attribute.Layout attrCodeEmpty; | ||
| 1693 | protected final Attribute.Layout attrInnerClassesEmpty; | ||
| 1694 | protected final Attribute.Layout attrClassFileVersion; | ||
| 1695 | protected final Attribute.Layout attrConstantValue; | ||
| 1696 | |||
| 1697 | // Mapping from Attribute.Layout to Integer (inverse of attrDefs) | ||
| 1698 | Map<Attribute.Layout, Integer> attrIndexTable = new HashMap<>(); | ||
| 1699 | |||
| 1700 | // Mapping from attribute index (<32 are flag bits) to attributes. | ||
| 1701 | protected List<List<Attribute.Layout>> attrDefs = | ||
| 1702 | new FixedList<>(ATTR_CONTEXT_LIMIT); | ||
| 1703 | { | ||
| 1704 | for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { | ||
| 1705 | assert(attrIndexLimit[i] == 0); | ||
| 1706 | attrIndexLimit[i] = 32; // just for the sake of predefs. | ||
| 1707 | attrDefs.set(i, new ArrayList<Attribute.Layout>(Collections.nCopies( | ||
| 1708 | attrIndexLimit[i], (Attribute.Layout)null))); | ||
| 1709 | |||
| 1710 | } | ||
| 1711 | |||
| 1712 | // Add predefined attribute definitions: | ||
| 1713 | attrInnerClassesEmpty = | ||
| 1714 | predefineAttribute(CLASS_ATTR_InnerClasses, ATTR_CONTEXT_CLASS, null, | ||
| 1715 | "InnerClasses", ""); | ||
| 1716 | assert(attrInnerClassesEmpty == Package.attrInnerClassesEmpty); | ||
| 1717 | predefineAttribute(CLASS_ATTR_SourceFile, ATTR_CONTEXT_CLASS, | ||
| 1718 | new Band[] { class_SourceFile_RUN }, | ||
| 1719 | "SourceFile", "RUNH"); | ||
| 1720 | predefineAttribute(CLASS_ATTR_EnclosingMethod, ATTR_CONTEXT_CLASS, | ||
| 1721 | new Band[] { | ||
| 1722 | class_EnclosingMethod_RC, | ||
| 1723 | class_EnclosingMethod_RDN | ||
| 1724 | }, | ||
| 1725 | "EnclosingMethod", "RCHRDNH"); | ||
| 1726 | attrClassFileVersion = | ||
| 1727 | predefineAttribute(CLASS_ATTR_ClassFile_version, ATTR_CONTEXT_CLASS, | ||
| 1728 | new Band[] { | ||
| 1729 | class_ClassFile_version_minor_H, | ||
| 1730 | class_ClassFile_version_major_H | ||
| 1731 | }, | ||
| 1732 | ".ClassFile.version", "HH"); | ||
| 1733 | predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_CLASS, | ||
| 1734 | new Band[] { class_Signature_RS }, | ||
| 1735 | "Signature", "RSH"); | ||
| 1736 | predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_CLASS, null, | ||
| 1737 | "Deprecated", ""); | ||
| 1738 | //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_CLASS, null, | ||
| 1739 | // "Synthetic", ""); | ||
| 1740 | predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_CLASS, null, | ||
| 1741 | ".Overflow", ""); | ||
| 1742 | attrConstantValue = | ||
| 1743 | predefineAttribute(FIELD_ATTR_ConstantValue, ATTR_CONTEXT_FIELD, | ||
| 1744 | new Band[] { field_ConstantValue_KQ }, | ||
| 1745 | "ConstantValue", "KQH"); | ||
| 1746 | predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_FIELD, | ||
| 1747 | new Band[] { field_Signature_RS }, | ||
| 1748 | "Signature", "RSH"); | ||
| 1749 | predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_FIELD, null, | ||
| 1750 | "Deprecated", ""); | ||
| 1751 | //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_FIELD, null, | ||
| 1752 | // "Synthetic", ""); | ||
| 1753 | predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_FIELD, null, | ||
| 1754 | ".Overflow", ""); | ||
| 1755 | attrCodeEmpty = | ||
| 1756 | predefineAttribute(METHOD_ATTR_Code, ATTR_CONTEXT_METHOD, null, | ||
| 1757 | "Code", ""); | ||
| 1758 | predefineAttribute(METHOD_ATTR_Exceptions, ATTR_CONTEXT_METHOD, | ||
| 1759 | new Band[] { | ||
| 1760 | method_Exceptions_N, | ||
| 1761 | method_Exceptions_RC | ||
| 1762 | }, | ||
| 1763 | "Exceptions", "NH[RCH]"); | ||
| 1764 | assert(attrCodeEmpty == Package.attrCodeEmpty); | ||
| 1765 | predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_METHOD, | ||
| 1766 | new Band[] { method_Signature_RS }, | ||
| 1767 | "Signature", "RSH"); | ||
| 1768 | predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_METHOD, null, | ||
| 1769 | "Deprecated", ""); | ||
| 1770 | //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_METHOD, null, | ||
| 1771 | // "Synthetic", ""); | ||
| 1772 | predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_METHOD, null, | ||
| 1773 | ".Overflow", ""); | ||
| 1774 | |||
| 1775 | for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) { | ||
| 1776 | MultiBand xxx_metadata_bands = metadataBands[ctype]; | ||
| 1777 | if (xxx_metadata_bands == null) | ||
| 1778 | continue; // no code attrs | ||
| 1779 | |||
| 1780 | // These arguments cause the bands to be built | ||
| 1781 | // automatically for this complicated layout: | ||
| 1782 | predefineAttribute(X_ATTR_RuntimeVisibleAnnotations, | ||
| 1783 | ATTR_CONTEXT_NAME[ctype]+"_RVA_", | ||
| 1784 | xxx_metadata_bands, | ||
| 1785 | Attribute.lookup(null, ctype, | ||
| 1786 | "RuntimeVisibleAnnotations")); | ||
| 1787 | predefineAttribute(X_ATTR_RuntimeInvisibleAnnotations, | ||
| 1788 | ATTR_CONTEXT_NAME[ctype]+"_RIA_", | ||
| 1789 | xxx_metadata_bands, | ||
| 1790 | Attribute.lookup(null, ctype, | ||
| 1791 | "RuntimeInvisibleAnnotations")); | ||
| 1792 | if (ctype != ATTR_CONTEXT_METHOD) | ||
| 1793 | continue; | ||
| 1794 | |||
| 1795 | predefineAttribute(METHOD_ATTR_RuntimeVisibleParameterAnnotations, | ||
| 1796 | "method_RVPA_", xxx_metadata_bands, | ||
| 1797 | Attribute.lookup(null, ctype, | ||
| 1798 | "RuntimeVisibleParameterAnnotations")); | ||
| 1799 | predefineAttribute(METHOD_ATTR_RuntimeInvisibleParameterAnnotations, | ||
| 1800 | "method_RIPA_", xxx_metadata_bands, | ||
| 1801 | Attribute.lookup(null, ctype, | ||
| 1802 | "RuntimeInvisibleParameterAnnotations")); | ||
| 1803 | predefineAttribute(METHOD_ATTR_AnnotationDefault, | ||
| 1804 | "method_AD_", xxx_metadata_bands, | ||
| 1805 | Attribute.lookup(null, ctype, | ||
| 1806 | "AnnotationDefault")); | ||
| 1807 | } | ||
| 1808 | |||
| 1809 | |||
| 1810 | Attribute.Layout stackMapDef = Attribute.lookup(null, ATTR_CONTEXT_CODE, "StackMapTable").layout(); | ||
| 1811 | predefineAttribute(CODE_ATTR_StackMapTable, ATTR_CONTEXT_CODE, | ||
| 1812 | stackmap_bands.toArray(), | ||
| 1813 | stackMapDef.name(), stackMapDef.layout()); | ||
| 1814 | |||
| 1815 | predefineAttribute(CODE_ATTR_LineNumberTable, ATTR_CONTEXT_CODE, | ||
| 1816 | new Band[] { | ||
| 1817 | code_LineNumberTable_N, | ||
| 1818 | code_LineNumberTable_bci_P, | ||
| 1819 | code_LineNumberTable_line | ||
| 1820 | }, | ||
| 1821 | "LineNumberTable", "NH[PHH]"); | ||
| 1822 | predefineAttribute(CODE_ATTR_LocalVariableTable, ATTR_CONTEXT_CODE, | ||
| 1823 | new Band[] { | ||
| 1824 | code_LocalVariableTable_N, | ||
| 1825 | code_LocalVariableTable_bci_P, | ||
| 1826 | code_LocalVariableTable_span_O, | ||
| 1827 | code_LocalVariableTable_name_RU, | ||
| 1828 | code_LocalVariableTable_type_RS, | ||
| 1829 | code_LocalVariableTable_slot | ||
| 1830 | }, | ||
| 1831 | "LocalVariableTable", "NH[PHOHRUHRSHH]"); | ||
| 1832 | predefineAttribute(CODE_ATTR_LocalVariableTypeTable, ATTR_CONTEXT_CODE, | ||
| 1833 | new Band[] { | ||
| 1834 | code_LocalVariableTypeTable_N, | ||
| 1835 | code_LocalVariableTypeTable_bci_P, | ||
| 1836 | code_LocalVariableTypeTable_span_O, | ||
| 1837 | code_LocalVariableTypeTable_name_RU, | ||
| 1838 | code_LocalVariableTypeTable_type_RS, | ||
| 1839 | code_LocalVariableTypeTable_slot | ||
| 1840 | }, | ||
| 1841 | "LocalVariableTypeTable", "NH[PHOHRUHRSHH]"); | ||
| 1842 | predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_CODE, null, | ||
| 1843 | ".Overflow", ""); | ||
| 1844 | |||
| 1845 | // Clear the record of having seen these definitions, | ||
| 1846 | // so they may be redefined without error. | ||
| 1847 | for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { | ||
| 1848 | attrDefSeen[i] = 0; | ||
| 1849 | } | ||
| 1850 | |||
| 1851 | // Set up the special masks: | ||
| 1852 | for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { | ||
| 1853 | attrOverflowMask[i] = (1<<X_ATTR_OVERFLOW); | ||
| 1854 | attrIndexLimit[i] = 0; // will make a final decision later | ||
| 1855 | } | ||
| 1856 | attrClassFileVersionMask = (1<<CLASS_ATTR_ClassFile_version); | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | private void adjustToMajver() { | ||
| 1860 | if (getPackageMajver() < JAVA6_PACKAGE_MAJOR_VERSION) { | ||
| 1861 | if (verbose > 0) Utils.log.fine("Legacy package version"); | ||
| 1862 | // Revoke definition of pre-1.6 attribute type. | ||
| 1863 | undefineAttribute(CODE_ATTR_StackMapTable, ATTR_CONTEXT_CODE); | ||
| 1864 | } | ||
| 1865 | } | ||
| 1866 | |||
| 1867 | protected void initAttrIndexLimit() { | ||
| 1868 | for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { | ||
| 1869 | assert(attrIndexLimit[i] == 0); // decide on it now! | ||
| 1870 | attrIndexLimit[i] = (haveFlagsHi(i)? 63: 32); | ||
| 1871 | List<Attribute.Layout> defList = attrDefs.get(i); | ||
| 1872 | assert(defList.size() == 32); // all predef indexes are <32 | ||
| 1873 | int addMore = attrIndexLimit[i] - defList.size(); | ||
| 1874 | defList.addAll(Collections.nCopies(addMore, (Attribute.Layout) null)); | ||
| 1875 | } | ||
| 1876 | } | ||
| 1877 | |||
| 1878 | protected boolean haveFlagsHi(int ctype) { | ||
| 1879 | int mask = 1<<(LG_AO_HAVE_XXX_FLAGS_HI+ctype); | ||
| 1880 | switch (ctype) { | ||
| 1881 | case ATTR_CONTEXT_CLASS: | ||
| 1882 | assert(mask == AO_HAVE_CLASS_FLAGS_HI); break; | ||
| 1883 | case ATTR_CONTEXT_FIELD: | ||
| 1884 | assert(mask == AO_HAVE_FIELD_FLAGS_HI); break; | ||
| 1885 | case ATTR_CONTEXT_METHOD: | ||
| 1886 | assert(mask == AO_HAVE_METHOD_FLAGS_HI); break; | ||
| 1887 | case ATTR_CONTEXT_CODE: | ||
| 1888 | assert(mask == AO_HAVE_CODE_FLAGS_HI); break; | ||
| 1889 | default: | ||
| 1890 | assert(false); | ||
| 1891 | } | ||
| 1892 | return testBit(archiveOptions, mask); | ||
| 1893 | } | ||
| 1894 | |||
| 1895 | protected List getPredefinedAttrs(int ctype) { | ||
| 1896 | assert(attrIndexLimit[ctype] != 0); | ||
| 1897 | List<Attribute.Layout> res = new ArrayList<>(attrIndexLimit[ctype]); | ||
| 1898 | // Remove nulls and non-predefs. | ||
| 1899 | for (int ai = 0; ai < attrIndexLimit[ctype]; ai++) { | ||
| 1900 | if (testBit(attrDefSeen[ctype], 1L<<ai)) continue; | ||
| 1901 | Attribute.Layout def = attrDefs.get(ctype).get(ai); | ||
| 1902 | if (def == null) continue; // unused flag bit | ||
| 1903 | assert(isPredefinedAttr(ctype, ai)); | ||
| 1904 | res.add(def); | ||
| 1905 | } | ||
| 1906 | return res; | ||
| 1907 | } | ||
| 1908 | |||
| 1909 | protected boolean isPredefinedAttr(int ctype, int ai) { | ||
| 1910 | assert(attrIndexLimit[ctype] != 0); | ||
| 1911 | // Overflow attrs are never predefined. | ||
| 1912 | if (ai >= attrIndexLimit[ctype]) return false; | ||
| 1913 | // If the bit is set, it was explicitly def'd. | ||
| 1914 | if (testBit(attrDefSeen[ctype], 1L<<ai)) return false; | ||
| 1915 | return (attrDefs.get(ctype).get(ai) != null); | ||
| 1916 | } | ||
| 1917 | |||
| 1918 | protected void adjustSpecialAttrMasks() { | ||
| 1919 | // Clear special masks if new definitions have been seen for them. | ||
| 1920 | attrClassFileVersionMask &= ~ attrDefSeen[ATTR_CONTEXT_CLASS]; | ||
| 1921 | // It is possible to clear the overflow mask (bit 16). | ||
| 1922 | for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { | ||
| 1923 | attrOverflowMask[i] &= ~ attrDefSeen[i]; | ||
| 1924 | } | ||
| 1925 | } | ||
| 1926 | |||
| 1927 | protected Attribute makeClassFileVersionAttr(int minver, int majver) { | ||
| 1928 | byte[] bytes = { | ||
| 1929 | (byte)(minver >> 8), (byte)minver, | ||
| 1930 | (byte)(majver >> 8), (byte)majver | ||
| 1931 | }; | ||
| 1932 | return attrClassFileVersion.addContent(bytes); | ||
| 1933 | } | ||
| 1934 | |||
| 1935 | protected short[] parseClassFileVersionAttr(Attribute attr) { | ||
| 1936 | assert(attr.layout() == attrClassFileVersion); | ||
| 1937 | assert(attr.size() == 4); | ||
| 1938 | byte[] bytes = attr.bytes(); | ||
| 1939 | int minver = ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF); | ||
| 1940 | int majver = ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF); | ||
| 1941 | return new short[]{ (short) minver, (short) majver }; | ||
| 1942 | } | ||
| 1943 | |||
| 1944 | private boolean assertBandOKForElems(Band[] ab, Attribute.Layout.Element[] elems) { | ||
| 1945 | for (int i = 0; i < elems.length; i++) { | ||
| 1946 | assert(assertBandOKForElem(ab, elems[i])); | ||
| 1947 | } | ||
| 1948 | return true; | ||
| 1949 | } | ||
| 1950 | private boolean assertBandOKForElem(Band[] ab, Attribute.Layout.Element e) { | ||
| 1951 | Band b = null; | ||
| 1952 | if (e.bandIndex != Attribute.NO_BAND_INDEX) | ||
| 1953 | b = ab[e.bandIndex]; | ||
| 1954 | Coding rc = UNSIGNED5; | ||
| 1955 | boolean wantIntBand = true; | ||
| 1956 | switch (e.kind) { | ||
| 1957 | case Attribute.EK_INT: | ||
| 1958 | if (e.flagTest(Attribute.EF_SIGN)) { | ||
| 1959 | rc = SIGNED5; | ||
| 1960 | } else if (e.len == 1) { | ||
| 1961 | rc = BYTE1; | ||
| 1962 | } | ||
| 1963 | break; | ||
| 1964 | case Attribute.EK_BCI: | ||
| 1965 | if (!e.flagTest(Attribute.EF_DELTA)) { | ||
| 1966 | rc = BCI5; | ||
| 1967 | } else { | ||
| 1968 | rc = BRANCH5; | ||
| 1969 | } | ||
| 1970 | break; | ||
| 1971 | case Attribute.EK_BCO: | ||
| 1972 | rc = BRANCH5; | ||
| 1973 | break; | ||
| 1974 | case Attribute.EK_FLAG: | ||
| 1975 | if (e.len == 1) rc = BYTE1; | ||
| 1976 | break; | ||
| 1977 | case Attribute.EK_REPL: | ||
| 1978 | if (e.len == 1) rc = BYTE1; | ||
| 1979 | assertBandOKForElems(ab, e.body); | ||
| 1980 | break; | ||
| 1981 | case Attribute.EK_UN: | ||
| 1982 | if (e.flagTest(Attribute.EF_SIGN)) { | ||
| 1983 | rc = SIGNED5; | ||
| 1984 | } else if (e.len == 1) { | ||
| 1985 | rc = BYTE1; | ||
| 1986 | } | ||
| 1987 | assertBandOKForElems(ab, e.body); | ||
| 1988 | break; | ||
| 1989 | case Attribute.EK_CASE: | ||
| 1990 | assert(b == null); | ||
| 1991 | assertBandOKForElems(ab, e.body); | ||
| 1992 | return true; // no direct band | ||
| 1993 | case Attribute.EK_CALL: | ||
| 1994 | assert(b == null); | ||
| 1995 | return true; // no direct band | ||
| 1996 | case Attribute.EK_CBLE: | ||
| 1997 | assert(b == null); | ||
| 1998 | assertBandOKForElems(ab, e.body); | ||
| 1999 | return true; // no direct band | ||
| 2000 | case Attribute.EK_REF: | ||
| 2001 | wantIntBand = false; | ||
| 2002 | assert(b instanceof CPRefBand); | ||
| 2003 | assert(((CPRefBand)b).nullOK == e.flagTest(Attribute.EF_NULL)); | ||
| 2004 | break; | ||
| 2005 | default: assert(false); | ||
| 2006 | } | ||
| 2007 | assert(b.regularCoding == rc) | ||
| 2008 | : (e+" // "+b); | ||
| 2009 | if (wantIntBand) | ||
| 2010 | assert(b instanceof IntBand); | ||
| 2011 | return true; | ||
| 2012 | } | ||
| 2013 | |||
| 2014 | private | ||
| 2015 | Attribute.Layout predefineAttribute(int index, int ctype, Band[] ab, | ||
| 2016 | String name, String layout) { | ||
| 2017 | // Use Attribute.find to get uniquification of layouts. | ||
| 2018 | Attribute.Layout def = Attribute.find(ctype, name, layout).layout(); | ||
| 2019 | //def.predef = true; | ||
| 2020 | if (index >= 0) { | ||
| 2021 | setAttributeLayoutIndex(def, index); | ||
| 2022 | } | ||
| 2023 | if (ab == null) { | ||
| 2024 | ab = new Band[0]; | ||
| 2025 | } | ||
| 2026 | assert(attrBandTable.get(def) == null); // no redef | ||
| 2027 | attrBandTable.put(def, ab); | ||
| 2028 | assert(def.bandCount == ab.length) | ||
| 2029 | : (def+" // "+Arrays.asList(ab)); | ||
| 2030 | // Let's make sure the band types match: | ||
| 2031 | assert(assertBandOKForElems(ab, def.elems)); | ||
| 2032 | return def; | ||
| 2033 | } | ||
| 2034 | |||
| 2035 | // This version takes bandPrefix/addHere instead of prebuilt Band[] ab. | ||
| 2036 | private | ||
| 2037 | Attribute.Layout predefineAttribute(int index, | ||
| 2038 | String bandPrefix, MultiBand addHere, | ||
| 2039 | Attribute attr) { | ||
| 2040 | //Attribute.Layout def = Attribute.find(ctype, name, layout).layout(); | ||
| 2041 | Attribute.Layout def = attr.layout(); | ||
| 2042 | int ctype = def.ctype(); | ||
| 2043 | return predefineAttribute(index, ctype, | ||
| 2044 | makeNewAttributeBands(bandPrefix, def, | ||
| 2045 | addHere), | ||
| 2046 | def.name(), def.layout()); | ||
| 2047 | } | ||
| 2048 | |||
| 2049 | private | ||
| 2050 | void undefineAttribute(int index, int ctype) { | ||
| 2051 | if (verbose > 1) { | ||
| 2052 | System.out.println("Removing predefined "+ATTR_CONTEXT_NAME[ctype]+ | ||
| 2053 | " attribute on bit "+index); | ||
| 2054 | } | ||
| 2055 | List<Attribute.Layout> defList = attrDefs.get(ctype); | ||
| 2056 | Attribute.Layout def = defList.get(index); | ||
| 2057 | assert(def != null); | ||
| 2058 | defList.set(index, null); | ||
| 2059 | attrIndexTable.put(def, null); | ||
| 2060 | // Clear the def bit. (For predefs, it's already clear.) | ||
| 2061 | assert(index < 64); | ||
| 2062 | attrDefSeen[ctype] &= ~(1L<<index); | ||
| 2063 | attrFlagMask[ctype] &= ~(1L<<index); | ||
| 2064 | Band[] ab = attrBandTable.get(def); | ||
| 2065 | for (int j = 0; j < ab.length; j++) { | ||
| 2066 | ab[j].doneWithUnusedBand(); | ||
| 2067 | } | ||
| 2068 | } | ||
| 2069 | |||
| 2070 | // Bands which contain non-predefined attrs. | ||
| 2071 | protected MultiBand[] attrBands = new MultiBand[ATTR_CONTEXT_LIMIT]; | ||
| 2072 | { | ||
| 2073 | attrBands[ATTR_CONTEXT_CLASS] = class_attr_bands; | ||
| 2074 | attrBands[ATTR_CONTEXT_FIELD] = field_attr_bands; | ||
| 2075 | attrBands[ATTR_CONTEXT_METHOD] = method_attr_bands; | ||
| 2076 | attrBands[ATTR_CONTEXT_CODE] = code_attr_bands; | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | // Create bands for all non-predefined attrs. | ||
| 2080 | void makeNewAttributeBands() { | ||
| 2081 | // Retract special flag bit bindings, if they were taken over. | ||
| 2082 | adjustSpecialAttrMasks(); | ||
| 2083 | |||
| 2084 | for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) { | ||
| 2085 | String cname = ATTR_CONTEXT_NAME[ctype]; | ||
| 2086 | MultiBand xxx_attr_bands = attrBands[ctype]; | ||
| 2087 | long defSeen = attrDefSeen[ctype]; | ||
| 2088 | // Note: attrDefSeen is always a subset of attrFlagMask. | ||
| 2089 | assert((defSeen & ~attrFlagMask[ctype]) == 0); | ||
| 2090 | for (int i = 0; i < attrDefs.get(ctype).size(); i++) { | ||
| 2091 | Attribute.Layout def = attrDefs.get(ctype).get(i); | ||
| 2092 | if (def == null) continue; // unused flag bit | ||
| 2093 | if (def.bandCount == 0) continue; // empty attr | ||
| 2094 | if (i < attrIndexLimit[ctype] && !testBit(defSeen, 1L<<i)) { | ||
| 2095 | // There are already predefined bands here. | ||
| 2096 | assert(attrBandTable.get(def) != null); | ||
| 2097 | continue; | ||
| 2098 | } | ||
| 2099 | int base = xxx_attr_bands.size(); | ||
| 2100 | String pfx = cname+"_"+def.name()+"_"; // debug only | ||
| 2101 | if (verbose > 1) | ||
| 2102 | Utils.log.fine("Making new bands for "+def); | ||
| 2103 | Band[] newAB = makeNewAttributeBands(pfx, def, | ||
| 2104 | xxx_attr_bands); | ||
| 2105 | assert(newAB.length == def.bandCount); | ||
| 2106 | Band[] prevAB = attrBandTable.put(def, newAB); | ||
| 2107 | if (prevAB != null) { | ||
| 2108 | // We won't be using these predefined bands. | ||
| 2109 | for (int j = 0; j < prevAB.length; j++) { | ||
| 2110 | prevAB[j].doneWithUnusedBand(); | ||
| 2111 | } | ||
| 2112 | } | ||
| 2113 | } | ||
| 2114 | } | ||
| 2115 | //System.out.println(prevForAssertMap); | ||
| 2116 | } | ||
| 2117 | private | ||
| 2118 | Band[] makeNewAttributeBands(String pfx, Attribute.Layout def, | ||
| 2119 | MultiBand addHere) { | ||
| 2120 | int base = addHere.size(); | ||
| 2121 | makeNewAttributeBands(pfx, def.elems, addHere); | ||
| 2122 | int nb = addHere.size() - base; | ||
| 2123 | Band[] newAB = new Band[nb]; | ||
| 2124 | for (int i = 0; i < nb; i++) { | ||
| 2125 | newAB[i] = addHere.get(base+i); | ||
| 2126 | } | ||
| 2127 | return newAB; | ||
| 2128 | } | ||
| 2129 | // Recursive helper, operates on a "body" or other sequence of elems: | ||
| 2130 | private | ||
| 2131 | void makeNewAttributeBands(String pfx, Attribute.Layout.Element[] elems, | ||
| 2132 | MultiBand ab) { | ||
| 2133 | for (int i = 0; i < elems.length; i++) { | ||
| 2134 | Attribute.Layout.Element e = elems[i]; | ||
| 2135 | String name = pfx+ab.size()+"_"+e.layout; | ||
| 2136 | { | ||
| 2137 | int tem; | ||
| 2138 | if ((tem = name.indexOf('[')) > 0) | ||
| 2139 | name = name.substring(0, tem); | ||
| 2140 | if ((tem = name.indexOf('(')) > 0) | ||
| 2141 | name = name.substring(0, tem); | ||
| 2142 | if (name.endsWith("H")) | ||
| 2143 | name = name.substring(0, name.length()-1); | ||
| 2144 | } | ||
| 2145 | Band nb; | ||
| 2146 | switch (e.kind) { | ||
| 2147 | case Attribute.EK_INT: | ||
| 2148 | nb = newElemBand(e, name, ab); | ||
| 2149 | break; | ||
| 2150 | case Attribute.EK_BCI: | ||
| 2151 | if (!e.flagTest(Attribute.EF_DELTA)) { | ||
| 2152 | // PH: transmit R(bci), store bci | ||
| 2153 | nb = ab.newIntBand(name, BCI5); | ||
| 2154 | } else { | ||
| 2155 | // POH: transmit D(R(bci)), store bci | ||
| 2156 | nb = ab.newIntBand(name, BRANCH5); | ||
| 2157 | } | ||
| 2158 | // Note: No case for BYTE1 here. | ||
| 2159 | break; | ||
| 2160 | case Attribute.EK_BCO: | ||
| 2161 | // OH: transmit D(R(bci)), store D(bci) | ||
| 2162 | nb = ab.newIntBand(name, BRANCH5); | ||
| 2163 | // Note: No case for BYTE1 here. | ||
| 2164 | break; | ||
| 2165 | case Attribute.EK_FLAG: | ||
| 2166 | assert(!e.flagTest(Attribute.EF_SIGN)); | ||
| 2167 | nb = newElemBand(e, name, ab); | ||
| 2168 | break; | ||
| 2169 | case Attribute.EK_REPL: | ||
| 2170 | assert(!e.flagTest(Attribute.EF_SIGN)); | ||
| 2171 | nb = newElemBand(e, name, ab); | ||
| 2172 | makeNewAttributeBands(pfx, e.body, ab); | ||
| 2173 | break; | ||
| 2174 | case Attribute.EK_UN: | ||
| 2175 | nb = newElemBand(e, name, ab); | ||
| 2176 | makeNewAttributeBands(pfx, e.body, ab); | ||
| 2177 | break; | ||
| 2178 | case Attribute.EK_CASE: | ||
| 2179 | if (!e.flagTest(Attribute.EF_BACK)) { | ||
| 2180 | // If it's not a duplicate body, make the bands. | ||
| 2181 | makeNewAttributeBands(pfx, e.body, ab); | ||
| 2182 | } | ||
| 2183 | continue; // no new band to make | ||
| 2184 | case Attribute.EK_REF: | ||
| 2185 | byte refKind = e.refKind; | ||
| 2186 | boolean nullOK = e.flagTest(Attribute.EF_NULL); | ||
| 2187 | nb = ab.newCPRefBand(name, UNSIGNED5, refKind, nullOK); | ||
| 2188 | // Note: No case for BYTE1 here. | ||
| 2189 | break; | ||
| 2190 | case Attribute.EK_CALL: | ||
| 2191 | continue; // no new band to make | ||
| 2192 | case Attribute.EK_CBLE: | ||
| 2193 | makeNewAttributeBands(pfx, e.body, ab); | ||
| 2194 | continue; // no new band to make | ||
| 2195 | default: assert(false); continue; | ||
| 2196 | } | ||
| 2197 | if (verbose > 1) { | ||
| 2198 | Utils.log.fine("New attribute band "+nb); | ||
| 2199 | } | ||
| 2200 | } | ||
| 2201 | } | ||
| 2202 | private | ||
| 2203 | Band newElemBand(Attribute.Layout.Element e, String name, MultiBand ab) { | ||
| 2204 | if (e.flagTest(Attribute.EF_SIGN)) { | ||
| 2205 | return ab.newIntBand(name, SIGNED5); | ||
| 2206 | } else if (e.len == 1) { | ||
| 2207 | return ab.newIntBand(name, BYTE1); // Not ByteBand, please. | ||
| 2208 | } else { | ||
| 2209 | return ab.newIntBand(name, UNSIGNED5); | ||
| 2210 | } | ||
| 2211 | } | ||
| 2212 | |||
| 2213 | protected int setAttributeLayoutIndex(Attribute.Layout def, int index) { | ||
| 2214 | int ctype = def.ctype; | ||
| 2215 | assert(ATTR_INDEX_OVERFLOW <= index && index < attrIndexLimit[ctype]); | ||
| 2216 | List<Attribute.Layout> defList = attrDefs.get(ctype); | ||
| 2217 | if (index == ATTR_INDEX_OVERFLOW) { | ||
| 2218 | // Overflow attribute. | ||
| 2219 | index = defList.size(); | ||
| 2220 | defList.add(def); | ||
| 2221 | if (verbose > 0) | ||
| 2222 | Utils.log.info("Adding new attribute at "+def +": "+index); | ||
| 2223 | attrIndexTable.put(def, index); | ||
| 2224 | return index; | ||
| 2225 | } | ||
| 2226 | |||
| 2227 | // Detect redefinitions: | ||
| 2228 | if (testBit(attrDefSeen[ctype], 1L<<index)) { | ||
| 2229 | throw new RuntimeException("Multiple explicit definition at "+index+": "+def); | ||
| 2230 | } | ||
| 2231 | attrDefSeen[ctype] |= (1L<<index); | ||
| 2232 | |||
| 2233 | // Adding a new fixed attribute. | ||
| 2234 | assert(0 <= index && index < attrIndexLimit[ctype]); | ||
| 2235 | if (verbose > (attrClassFileVersionMask == 0? 2:0)) | ||
| 2236 | Utils.log.fine("Fixing new attribute at "+index | ||
| 2237 | +": "+def | ||
| 2238 | +(defList.get(index) == null? "": | ||
| 2239 | "; replacing "+defList.get(index))); | ||
| 2240 | attrFlagMask[ctype] |= (1L<<index); | ||
| 2241 | // Remove index binding of any previous fixed attr. | ||
| 2242 | attrIndexTable.put(defList.get(index), null); | ||
| 2243 | defList.set(index, def); | ||
| 2244 | attrIndexTable.put(def, index); | ||
| 2245 | return index; | ||
| 2246 | } | ||
| 2247 | |||
| 2248 | // encodings found in the code_headers band | ||
| 2249 | private static final int[][] shortCodeLimits = { | ||
| 2250 | { 12, 12 }, // s<12, l<12, e=0 [1..144] | ||
| 2251 | { 8, 8 }, // s<8, l<8, e=1 [145..208] | ||
| 2252 | { 7, 7 }, // s<7, l<7, e=2 [209..256] | ||
| 2253 | }; | ||
| 2254 | public final int shortCodeHeader_h_limit = shortCodeLimits.length; | ||
| 2255 | |||
| 2256 | // return 0 if it won't encode, else a number in [1..255] | ||
| 2257 | static int shortCodeHeader(Code code) { | ||
| 2258 | int s = code.max_stack; | ||
| 2259 | int l0 = code.max_locals; | ||
| 2260 | int h = code.handler_class.length; | ||
| 2261 | if (h >= shortCodeLimits.length) return LONG_CODE_HEADER; | ||
| 2262 | int siglen = code.getMethod().getArgumentSize(); | ||
| 2263 | assert(l0 >= siglen); // enough locals for signature! | ||
| 2264 | if (l0 < siglen) return LONG_CODE_HEADER; | ||
| 2265 | int l1 = l0 - siglen; // do not count locals required by the signature | ||
| 2266 | int lims = shortCodeLimits[h][0]; | ||
| 2267 | int liml = shortCodeLimits[h][1]; | ||
| 2268 | if (s >= lims || l1 >= liml) return LONG_CODE_HEADER; | ||
| 2269 | int sc = shortCodeHeader_h_base(h); | ||
| 2270 | sc += s + lims*l1; | ||
| 2271 | if (sc > 255) return LONG_CODE_HEADER; | ||
| 2272 | assert(shortCodeHeader_max_stack(sc) == s); | ||
| 2273 | assert(shortCodeHeader_max_na_locals(sc) == l1); | ||
| 2274 | assert(shortCodeHeader_handler_count(sc) == h); | ||
| 2275 | return sc; | ||
| 2276 | } | ||
| 2277 | |||
| 2278 | static final int LONG_CODE_HEADER = 0; | ||
| 2279 | static int shortCodeHeader_handler_count(int sc) { | ||
| 2280 | assert(sc > 0 && sc <= 255); | ||
| 2281 | for (int h = 0; ; h++) { | ||
| 2282 | if (sc < shortCodeHeader_h_base(h+1)) | ||
| 2283 | return h; | ||
| 2284 | } | ||
| 2285 | } | ||
| 2286 | static int shortCodeHeader_max_stack(int sc) { | ||
| 2287 | int h = shortCodeHeader_handler_count(sc); | ||
| 2288 | int lims = shortCodeLimits[h][0]; | ||
| 2289 | return (sc - shortCodeHeader_h_base(h)) % lims; | ||
| 2290 | } | ||
| 2291 | static int shortCodeHeader_max_na_locals(int sc) { | ||
| 2292 | int h = shortCodeHeader_handler_count(sc); | ||
| 2293 | int lims = shortCodeLimits[h][0]; | ||
| 2294 | return (sc - shortCodeHeader_h_base(h)) / lims; | ||
| 2295 | } | ||
| 2296 | |||
| 2297 | private static int shortCodeHeader_h_base(int h) { | ||
| 2298 | assert(h <= shortCodeLimits.length); | ||
| 2299 | int sc = 1; | ||
| 2300 | for (int h0 = 0; h0 < h; h0++) { | ||
| 2301 | int lims = shortCodeLimits[h0][0]; | ||
| 2302 | int liml = shortCodeLimits[h0][1]; | ||
| 2303 | sc += lims * liml; | ||
| 2304 | } | ||
| 2305 | return sc; | ||
| 2306 | } | ||
| 2307 | |||
| 2308 | // utilities for accessing the bc_label band: | ||
| 2309 | protected void putLabel(IntBand bc_label, Code c, int pc, int targetPC) { | ||
| 2310 | bc_label.putInt(c.encodeBCI(targetPC) - c.encodeBCI(pc)); | ||
| 2311 | } | ||
| 2312 | protected int getLabel(IntBand bc_label, Code c, int pc) { | ||
| 2313 | return c.decodeBCI(bc_label.getInt() + c.encodeBCI(pc)); | ||
| 2314 | } | ||
| 2315 | |||
| 2316 | protected CPRefBand getCPRefOpBand(int bc) { | ||
| 2317 | switch (Instruction.getCPRefOpTag(bc)) { | ||
| 2318 | case CONSTANT_Class: | ||
| 2319 | return bc_classref; | ||
| 2320 | case CONSTANT_Fieldref: | ||
| 2321 | return bc_fieldref; | ||
| 2322 | case CONSTANT_Methodref: | ||
| 2323 | return bc_methodref; | ||
| 2324 | case CONSTANT_InterfaceMethodref: | ||
| 2325 | return bc_imethodref; | ||
| 2326 | case CONSTANT_Literal: | ||
| 2327 | switch (bc) { | ||
| 2328 | case _ildc: case _ildc_w: | ||
| 2329 | return bc_intref; | ||
| 2330 | case _fldc: case _fldc_w: | ||
| 2331 | return bc_floatref; | ||
| 2332 | case _lldc2_w: | ||
| 2333 | return bc_longref; | ||
| 2334 | case _dldc2_w: | ||
| 2335 | return bc_doubleref; | ||
| 2336 | case _aldc: case _aldc_w: | ||
| 2337 | return bc_stringref; | ||
| 2338 | case _cldc: case _cldc_w: | ||
| 2339 | return bc_classref; | ||
| 2340 | } | ||
| 2341 | break; | ||
| 2342 | } | ||
| 2343 | assert(false); | ||
| 2344 | return null; | ||
| 2345 | } | ||
| 2346 | |||
| 2347 | protected CPRefBand selfOpRefBand(int self_bc) { | ||
| 2348 | assert(Instruction.isSelfLinkerOp(self_bc)); | ||
| 2349 | int idx = (self_bc - _self_linker_op); | ||
| 2350 | boolean isSuper = (idx >= _self_linker_super_flag); | ||
| 2351 | if (isSuper) idx -= _self_linker_super_flag; | ||
| 2352 | boolean isAload = (idx >= _self_linker_aload_flag); | ||
| 2353 | if (isAload) idx -= _self_linker_aload_flag; | ||
| 2354 | int origBC = _first_linker_op + idx; | ||
| 2355 | boolean isField = Instruction.isFieldOp(origBC); | ||
| 2356 | if (!isSuper) | ||
| 2357 | return isField? bc_thisfield: bc_thismethod; | ||
| 2358 | else | ||
| 2359 | return isField? bc_superfield: bc_supermethod; | ||
| 2360 | } | ||
| 2361 | |||
| 2362 | //////////////////////////////////////////////////////////////////// | ||
| 2363 | |||
| 2364 | static int nextSeqForDebug; | ||
| 2365 | static File dumpDir = null; | ||
| 2366 | static OutputStream getDumpStream(Band b, String ext) throws IOException { | ||
| 2367 | return getDumpStream(b.name, b.seqForDebug, ext, b); | ||
| 2368 | } | ||
| 2369 | static OutputStream getDumpStream(Index ix, String ext) throws IOException { | ||
| 2370 | if (ix.size() == 0) return new ByteArrayOutputStream(); | ||
| 2371 | int seq = ConstantPool.TAG_ORDER[ix.cpMap[0].tag]; | ||
| 2372 | return getDumpStream(ix.debugName, seq, ext, ix); | ||
| 2373 | } | ||
| 2374 | static OutputStream getDumpStream(String name, int seq, String ext, Object b) throws IOException { | ||
| 2375 | if (dumpDir == null) { | ||
| 2376 | dumpDir = File.createTempFile("BD_", "", new File(".")); | ||
| 2377 | dumpDir.delete(); | ||
| 2378 | if (dumpDir.mkdir()) | ||
| 2379 | Utils.log.info("Dumping bands to "+dumpDir); | ||
| 2380 | } | ||
| 2381 | name = name.replace('(', ' ').replace(')', ' '); | ||
| 2382 | name = name.replace('/', ' '); | ||
| 2383 | name = name.replace('*', ' '); | ||
| 2384 | name = name.trim().replace(' ','_'); | ||
| 2385 | name = ((10000+seq) + "_" + name).substring(1); | ||
| 2386 | File dumpFile = new File(dumpDir, name+ext); | ||
| 2387 | Utils.log.info("Dumping "+b+" to "+dumpFile); | ||
| 2388 | return new BufferedOutputStream(new FileOutputStream(dumpFile)); | ||
| 2389 | } | ||
| 2390 | |||
| 2391 | // DEBUG ONLY: Validate me at each length change. | ||
| 2392 | static boolean assertCanChangeLength(Band b) { | ||
| 2393 | switch (b.phase) { | ||
| 2394 | case COLLECT_PHASE: | ||
| 2395 | case READ_PHASE: | ||
| 2396 | return true; | ||
| 2397 | } | ||
| 2398 | return false; | ||
| 2399 | } | ||
| 2400 | |||
| 2401 | // DEBUG ONLY: Validate a phase. | ||
| 2402 | static boolean assertPhase(Band b, int phaseExpected) { | ||
| 2403 | if (b.phase() != phaseExpected) { | ||
| 2404 | Utils.log.warning("phase expected "+phaseExpected+" was "+b.phase()+" in "+b); | ||
| 2405 | return false; | ||
| 2406 | } | ||
| 2407 | return true; | ||
| 2408 | } | ||
| 2409 | |||
| 2410 | |||
| 2411 | // DEBUG ONLY: Tells whether verbosity is turned on. | ||
| 2412 | static int verbose() { | ||
| 2413 | return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE); | ||
| 2414 | } | ||
| 2415 | |||
| 2416 | |||
| 2417 | // DEBUG ONLY: Validate me at each phase change. | ||
| 2418 | static boolean assertPhaseChangeOK(Band b, int p0, int p1) { | ||
| 2419 | switch (p0*10+p1) { | ||
| 2420 | /// Writing phases: | ||
| 2421 | case NO_PHASE*10+COLLECT_PHASE: | ||
| 2422 | // Ready to collect data from the input classes. | ||
| 2423 | assert(!b.isReader()); | ||
| 2424 | assert(b.capacity() >= 0); | ||
| 2425 | assert(b.length() == 0); | ||
| 2426 | return true; | ||
| 2427 | case COLLECT_PHASE*10+FROZEN_PHASE: | ||
| 2428 | case FROZEN_PHASE*10+FROZEN_PHASE: | ||
| 2429 | assert(b.length() == 0); | ||
| 2430 | return true; | ||
| 2431 | case COLLECT_PHASE*10+WRITE_PHASE: | ||
| 2432 | case FROZEN_PHASE*10+WRITE_PHASE: | ||
| 2433 | // Data is all collected. Ready to write bytes to disk. | ||
| 2434 | return true; | ||
| 2435 | case WRITE_PHASE*10+DONE_PHASE: | ||
| 2436 | // Done writing to disk. Ready to reset, in principle. | ||
| 2437 | return true; | ||
| 2438 | |||
| 2439 | /// Reading phases: | ||
| 2440 | case NO_PHASE*10+EXPECT_PHASE: | ||
| 2441 | assert(b.isReader()); | ||
| 2442 | assert(b.capacity() < 0); | ||
| 2443 | return true; | ||
| 2444 | case EXPECT_PHASE*10+READ_PHASE: | ||
| 2445 | // Ready to read values from disk. | ||
| 2446 | assert(Math.max(0,b.capacity()) >= b.valuesExpected()); | ||
| 2447 | assert(b.length() <= 0); | ||
| 2448 | return true; | ||
| 2449 | case READ_PHASE*10+DISBURSE_PHASE: | ||
| 2450 | // Ready to disburse values. | ||
| 2451 | assert(b.valuesRemainingForDebug() == b.length()); | ||
| 2452 | return true; | ||
| 2453 | case DISBURSE_PHASE*10+DONE_PHASE: | ||
| 2454 | // Done disbursing values. Ready to reset, in principle. | ||
| 2455 | assert(assertDoneDisbursing(b)); | ||
| 2456 | return true; | ||
| 2457 | } | ||
| 2458 | if (p0 == p1) | ||
| 2459 | Utils.log.warning("Already in phase "+p0); | ||
| 2460 | else | ||
| 2461 | Utils.log.warning("Unexpected phase "+p0+" -> "+p1); | ||
| 2462 | return false; | ||
| 2463 | } | ||
| 2464 | |||
| 2465 | static private boolean assertDoneDisbursing(Band b) { | ||
| 2466 | if (b.phase != DISBURSE_PHASE) { | ||
| 2467 | Utils.log.warning("assertDoneDisbursing: still in phase "+b.phase+": "+b); | ||
| 2468 | if (verbose() <= 1) return false; // fail now | ||
| 2469 | } | ||
| 2470 | int left = b.valuesRemainingForDebug(); | ||
| 2471 | if (left > 0) { | ||
| 2472 | Utils.log.warning("assertDoneDisbursing: "+left+" values left in "+b); | ||
| 2473 | if (verbose() <= 1) return false; // fail now | ||
| 2474 | } | ||
| 2475 | if (b instanceof MultiBand) { | ||
| 2476 | MultiBand mb = (MultiBand) b; | ||
| 2477 | for (int i = 0; i < mb.bandCount; i++) { | ||
| 2478 | Band sub = mb.bands[i]; | ||
| 2479 | if (sub.phase != DONE_PHASE) { | ||
| 2480 | Utils.log.warning("assertDoneDisbursing: sub-band still in phase "+sub.phase+": "+sub); | ||
| 2481 | if (verbose() <= 1) return false; // fail now | ||
| 2482 | } | ||
| 2483 | } | ||
| 2484 | } | ||
| 2485 | return true; | ||
| 2486 | } | ||
| 2487 | |||
| 2488 | static private void printCDecl(Band b) { | ||
| 2489 | if (b instanceof MultiBand) { | ||
| 2490 | MultiBand mb = (MultiBand) b; | ||
| 2491 | for (int i = 0; i < mb.bandCount; i++) { | ||
| 2492 | printCDecl(mb.bands[i]); | ||
| 2493 | } | ||
| 2494 | return; | ||
| 2495 | } | ||
| 2496 | String ixS = "NULL"; | ||
| 2497 | if (b instanceof CPRefBand) { | ||
| 2498 | Index ix = ((CPRefBand)b).index; | ||
| 2499 | if (ix != null) ixS = "INDEX("+ix.debugName+")"; | ||
| 2500 | } | ||
| 2501 | Coding[] knownc = { BYTE1, CHAR3, BCI5, BRANCH5, UNSIGNED5, | ||
| 2502 | UDELTA5, SIGNED5, DELTA5, MDELTA5 }; | ||
| 2503 | String[] knowns = { "BYTE1", "CHAR3", "BCI5", "BRANCH5", "UNSIGNED5", | ||
| 2504 | "UDELTA5", "SIGNED5", "DELTA5", "MDELTA5" }; | ||
| 2505 | Coding rc = b.regularCoding; | ||
| 2506 | int rci = Arrays.asList(knownc).indexOf(rc); | ||
| 2507 | String cstr; | ||
| 2508 | if (rci >= 0) | ||
| 2509 | cstr = knowns[rci]; | ||
| 2510 | else | ||
| 2511 | cstr = "CODING"+rc.keyString(); | ||
| 2512 | System.out.println(" BAND_INIT(\""+b.name()+"\"" | ||
| 2513 | +", "+cstr+", "+ixS+"),"); | ||
| 2514 | } | ||
| 2515 | |||
| 2516 | private Map<Band, Band> prevForAssertMap; | ||
| 2517 | |||
| 2518 | // DEBUG ONLY: Record something about the band order. | ||
| 2519 | boolean notePrevForAssert(Band b, Band p) { | ||
| 2520 | if (prevForAssertMap == null) | ||
| 2521 | prevForAssertMap = new HashMap<>(); | ||
| 2522 | prevForAssertMap.put(b, p); | ||
| 2523 | return true; | ||
| 2524 | } | ||
| 2525 | |||
| 2526 | // DEBUG ONLY: Validate next input band. | ||
| 2527 | private boolean assertReadyToReadFrom(Band b, InputStream in) throws IOException { | ||
| 2528 | Band p = prevForAssertMap.get(b); | ||
| 2529 | // Any previous band must be done reading before this one starts. | ||
| 2530 | if (p != null && phaseCmp(p.phase(), DISBURSE_PHASE) < 0) { | ||
| 2531 | Utils.log.warning("Previous band not done reading."); | ||
| 2532 | Utils.log.info(" Previous band: "+p); | ||
| 2533 | Utils.log.info(" Next band: "+b); | ||
| 2534 | Thread.dumpStack(); | ||
| 2535 | assert(verbose > 0); // die unless verbose is true | ||
| 2536 | } | ||
| 2537 | String name = b.name; | ||
| 2538 | if (optDebugBands && !name.startsWith("(")) { | ||
| 2539 | // Verify synchronization between reader & writer: | ||
| 2540 | StringBuilder buf = new StringBuilder(); | ||
| 2541 | int ch; | ||
| 2542 | while ((ch = in.read()) > 0) | ||
| 2543 | buf.append((char)ch); | ||
| 2544 | String inName = buf.toString(); | ||
| 2545 | if (!inName.equals(name)) { | ||
| 2546 | StringBuilder sb = new StringBuilder(); | ||
| 2547 | sb.append("Expected "+name+" but read: "); | ||
| 2548 | inName += (char)ch; | ||
| 2549 | while (inName.length() < 10) { | ||
| 2550 | inName += (char) in.read(); | ||
| 2551 | } | ||
| 2552 | for (int i = 0; i < inName.length(); i++) { | ||
| 2553 | sb.append(inName.charAt(i)); | ||
| 2554 | } | ||
| 2555 | Utils.log.warning(sb.toString()); | ||
| 2556 | return false; | ||
| 2557 | } | ||
| 2558 | } | ||
| 2559 | return true; | ||
| 2560 | } | ||
| 2561 | |||
| 2562 | // DEBUG ONLY: Make sure a bunch of cprefs are correct. | ||
| 2563 | private boolean assertValidCPRefs(CPRefBand b) { | ||
| 2564 | if (b.index == null) return true; | ||
| 2565 | int limit = b.index.size()+1; | ||
| 2566 | for (int i = 0; i < b.length(); i++) { | ||
| 2567 | int v = b.valueAtForDebug(i); | ||
| 2568 | if (v < 0 || v >= limit) { | ||
| 2569 | Utils.log.warning("CP ref out of range "+ | ||
| 2570 | "["+i+"] = "+v+" in "+b); | ||
| 2571 | return false; | ||
| 2572 | } | ||
| 2573 | } | ||
| 2574 | return true; | ||
| 2575 | } | ||
| 2576 | |||
| 2577 | // DEBUG ONLY: Maybe write a debugging cookie to next output band. | ||
| 2578 | private boolean assertReadyToWriteTo(Band b, OutputStream out) throws IOException { | ||
| 2579 | Band p = prevForAssertMap.get(b); | ||
| 2580 | // Any previous band must be done writing before this one starts. | ||
| 2581 | if (p != null && phaseCmp(p.phase(), DONE_PHASE) < 0) { | ||
| 2582 | Utils.log.warning("Previous band not done writing."); | ||
| 2583 | Utils.log.info(" Previous band: "+p); | ||
| 2584 | Utils.log.info(" Next band: "+b); | ||
| 2585 | Thread.dumpStack(); | ||
| 2586 | assert(verbose > 0); // die unless verbose is true | ||
| 2587 | } | ||
| 2588 | String name = b.name; | ||
| 2589 | if (optDebugBands && !name.startsWith("(")) { | ||
| 2590 | // Verify synchronization between reader & writer: | ||
| 2591 | for (int j = 0; j < name.length(); j++) { | ||
| 2592 | out.write((byte)name.charAt(j)); | ||
| 2593 | } | ||
| 2594 | out.write((byte)0); | ||
| 2595 | } | ||
| 2596 | return true; | ||
| 2597 | } | ||
| 2598 | |||
| 2599 | protected static boolean testBit(int flags, int bitMask) { | ||
| 2600 | return (flags & bitMask) != 0; | ||
| 2601 | } | ||
| 2602 | protected static int setBit(int flags, int bitMask, boolean z) { | ||
| 2603 | return z ? (flags | bitMask) : (flags &~ bitMask); | ||
| 2604 | } | ||
| 2605 | protected static boolean testBit(long flags, long bitMask) { | ||
| 2606 | return (flags & bitMask) != 0; | ||
| 2607 | } | ||
| 2608 | protected static long setBit(long flags, long bitMask, boolean z) { | ||
| 2609 | return z ? (flags | bitMask) : (flags &~ bitMask); | ||
| 2610 | } | ||
| 2611 | |||
| 2612 | |||
| 2613 | static void printArrayTo(PrintStream ps, int[] values, int start, int end) { | ||
| 2614 | int len = end-start; | ||
| 2615 | for (int i = 0; i < len; i++) { | ||
| 2616 | if (i % 10 == 0) | ||
| 2617 | ps.println(); | ||
| 2618 | else | ||
| 2619 | ps.print(" "); | ||
| 2620 | ps.print(values[start+i]); | ||
| 2621 | } | ||
| 2622 | ps.println(); | ||
| 2623 | } | ||
| 2624 | |||
| 2625 | static void printArrayTo(PrintStream ps, Entry[] cpMap, int start, int end) { | ||
| 2626 | StringBuffer buf = new StringBuffer(); | ||
| 2627 | int len = end-start; | ||
| 2628 | for (int i = 0; i < len; i++) { | ||
| 2629 | String s = cpMap[start+i].stringValue(); | ||
| 2630 | buf.setLength(0); | ||
| 2631 | for (int j = 0; j < s.length(); j++) { | ||
| 2632 | char ch = s.charAt(j); | ||
| 2633 | if (!(ch < ' ' || ch > '~' || ch == '\\')) { | ||
| 2634 | buf.append(ch); | ||
| 2635 | } else if (ch == '\n') { | ||
| 2636 | buf.append("\\n"); | ||
| 2637 | } else if (ch == '\t') { | ||
| 2638 | buf.append("\\t"); | ||
| 2639 | } else if (ch == '\r') { | ||
| 2640 | buf.append("\\r"); | ||
| 2641 | } else { | ||
| 2642 | buf.append("\\x"+Integer.toHexString(ch)); | ||
| 2643 | } | ||
| 2644 | } | ||
| 2645 | ps.println(buf); | ||
| 2646 | } | ||
| 2647 | } | ||
| 2648 | |||
| 2649 | |||
| 2650 | // Utilities for reallocating: | ||
| 2651 | protected static Object[] realloc(Object[] a, int len) { | ||
| 2652 | java.lang.Class elt = a.getClass().getComponentType(); | ||
| 2653 | Object[] na = (Object[]) java.lang.reflect.Array.newInstance(elt, len); | ||
| 2654 | System.arraycopy(a, 0, na, 0, Math.min(a.length, len)); | ||
| 2655 | return na; | ||
| 2656 | } | ||
| 2657 | protected static Object[] realloc(Object[] a) { | ||
| 2658 | return realloc(a, Math.max(10, a.length*2)); | ||
| 2659 | } | ||
| 2660 | |||
| 2661 | protected static int[] realloc(int[] a, int len) { | ||
| 2662 | if (len == 0) return noInts; | ||
| 2663 | if (a == null) return new int[len]; | ||
| 2664 | int[] na = new int[len]; | ||
| 2665 | System.arraycopy(a, 0, na, 0, Math.min(a.length, len)); | ||
| 2666 | return na; | ||
| 2667 | } | ||
| 2668 | protected static int[] realloc(int[] a) { | ||
| 2669 | return realloc(a, Math.max(10, a.length*2)); | ||
| 2670 | } | ||
| 2671 | |||
| 2672 | protected static byte[] realloc(byte[] a, int len) { | ||
| 2673 | if (len == 0) return noBytes; | ||
| 2674 | if (a == null) return new byte[len]; | ||
| 2675 | byte[] na = new byte[len]; | ||
| 2676 | System.arraycopy(a, 0, na, 0, Math.min(a.length, len)); | ||
| 2677 | return na; | ||
| 2678 | } | ||
| 2679 | protected static byte[] realloc(byte[] a) { | ||
| 2680 | return realloc(a, Math.max(10, a.length*2)); | ||
| 2681 | } | ||
| 2682 | } | ||