blob: f2009096ef32fb3cb2e7f42a7e4c47efdf29b9bb [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.java.util.jar.pack;
27
28import java.io.*;
29import java.util.*;
30import com.sun.java.util.jar.pack.ConstantPool.*;
31
32/**
33 * Collection of relocatable constant pool references.
34 * It operates with respect to a particular byte array,
35 * and stores some of its state in the bytes themselves.
36 * <p>
37 * As a Collection, it can be iterated over, but it is not a List,
38 * since it does not natively support indexed access.
39 * <p>
40 *
41 * @author John Rose
42 */
43class Fixups extends AbstractCollection implements Constants {
44 byte[] bytes; // the subject of the relocations
45 int head; // desc locating first reloc
46 int tail; // desc locating last reloc
47 int size; // number of relocations
48 Entry[] entries; // [0..size-1] relocations
49 int[] bigDescs; // descs which cannot be stored in the bytes
50
51 // A "desc" (descriptor) is a bit-encoded pair of a location
52 // and format. Every fixup occurs at a "desc". Until final
53 // patching, bytes addressed by descs may also be used to
54 // link this data structure together. If the bytes are missing,
55 // or if the "desc" is too large to encode in the bytes,
56 // it is kept in the bigDescs array.
57
58 Fixups(byte[] bytes) {
59 this.bytes = bytes;
60 entries = new Entry[3];
61 bigDescs = noBigDescs;
62 }
63 Fixups() {
64 // If there are no bytes, all descs are kept in bigDescs.
65 this((byte[])null);
66 }
67 Fixups(byte[] bytes, Collection fixups) {
68 this(bytes);
69 addAll(fixups);
70 }
71 Fixups(Collection fixups) {
72 this((byte[])null);
73 addAll(fixups);
74 }
75
76 private static final int MINBIGSIZE = 1;
77 // cleverly share empty bigDescs:
78 private static int[] noBigDescs = {MINBIGSIZE};
79
80 public int size() {
81 return size;
82 }
83
84 public void trimToSize() {
85 if (size != entries.length) {
86 Entry[] oldEntries = entries;
87 entries = new Entry[size];
88 System.arraycopy(oldEntries, 0, entries, 0, size);
89 }
90 int bigSize = bigDescs[BIGSIZE];
91 if (bigSize == MINBIGSIZE) {
92 bigDescs = noBigDescs;
93 } else if (bigSize != bigDescs.length) {
94 int[] oldBigDescs = bigDescs;
95 bigDescs = new int[bigSize];
96 System.arraycopy(oldBigDescs, 0, bigDescs, 0, bigSize);
97 }
98 }
99
100 public void visitRefs(Collection refs) {
101 for (int i = 0; i < size; i++) {
102 refs.add(entries[i]);
103 }
104 }
105
106 public void clear() {
107 if (bytes != null) {
108 // Clean the bytes:
109 for (Iterator i = iterator(); i.hasNext(); ) {
110 Fixup fx = (Fixup) i.next();
111 //System.out.println("clean "+fx);
112 storeIndex(fx.location(), fx.format(), 0);
113 }
114 }
115 size = 0;
116 if (bigDescs != noBigDescs)
117 bigDescs[BIGSIZE] = MINBIGSIZE;
118 // do not trim to size, however
119 }
120
121 public byte[] getBytes() {
122 return bytes;
123 }
124
125 public void setBytes(byte[] newBytes) {
126 if (bytes == newBytes) return;
127 ArrayList old = null;
128 assert((old = new ArrayList(this)) != null);
129 if (bytes == null || newBytes == null) {
130 // One or the other representations is deficient.
131 // Construct a checkpoint.
132 ArrayList save = new ArrayList(this);
133 clear();
134 bytes = newBytes;
135 addAll(save);
136 } else {
137 // assume newBytes is some sort of bitwise copy of the old bytes
138 bytes = newBytes;
139 }
140 assert(old.equals(new ArrayList(this)));
141 }
142
143 static final int LOC_SHIFT = 1;
144 static final int FMT_MASK = 0x1;
145 static final byte UNUSED_BYTE = 0;
146 static final byte OVERFLOW_BYTE = -1;
147 // fill pointer of bigDescs array is in element [0]
148 static final int BIGSIZE = 0;
149
150 // Format values:
151 public static final int U2_FORMAT = 0;
152 public static final int U1_FORMAT = 1;
153
154 // Special values for the static methods.
155 private static final int SPECIAL_LOC = 0;
156 private static final int SPECIAL_FMT = U2_FORMAT;
157
158 static int fmtLen(int fmt) { return 1+(fmt-U1_FORMAT)/(U2_FORMAT-U1_FORMAT); }
159 static int descLoc(int desc) { return desc >>> LOC_SHIFT; }
160 static int descFmt(int desc) { return desc & FMT_MASK; }
161 static int descEnd(int desc) { return descLoc(desc) + fmtLen(descFmt(desc)); }
162 static int makeDesc(int loc, int fmt) {
163 int desc = (loc << LOC_SHIFT) | fmt;
164 assert(descLoc(desc) == loc);
165 assert(descFmt(desc) == fmt);
166 return desc;
167 }
168 int fetchDesc(int loc, int fmt) {
169 byte b1 = bytes[loc];
170 assert(b1 != OVERFLOW_BYTE);
171 int value;
172 if (fmt == U2_FORMAT) {
173 byte b2 = bytes[loc+1];
174 value = ((b1 & 0xFF) << 8) + (b2 & 0xFF);
175 } else {
176 value = (b1 & 0xFF);
177 }
178 // Stored loc field is difference between its own loc and next loc.
179 return value + (loc << LOC_SHIFT);
180 }
181 boolean storeDesc(int loc, int fmt, int desc) {
182 if (bytes == null)
183 return false;
184 int value = desc - (loc << LOC_SHIFT);
185 byte b1, b2;
186 switch (fmt) {
187 case U2_FORMAT:
188 assert(bytes[loc+0] == UNUSED_BYTE);
189 assert(bytes[loc+1] == UNUSED_BYTE);
190 b1 = (byte)(value >> 8);
191 b2 = (byte)(value >> 0);
192 if (value == (value & 0xFFFF) && b1 != OVERFLOW_BYTE) {
193 bytes[loc+0] = b1;
194 bytes[loc+1] = b2;
195 assert(fetchDesc(loc, fmt) == desc);
196 return true;
197 }
198 break;
199 case U1_FORMAT:
200 assert(bytes[loc] == UNUSED_BYTE);
201 b1 = (byte)value;
202 if (value == (value & 0xFF) && b1 != OVERFLOW_BYTE) {
203 bytes[loc] = b1;
204 assert(fetchDesc(loc, fmt) == desc);
205 return true;
206 }
207 break;
208 default: assert(false);
209 }
210 // Failure. Caller must allocate a bigDesc.
211 bytes[loc] = OVERFLOW_BYTE;
212 assert(fmt==U1_FORMAT || (bytes[loc+1]=(byte)bigDescs[BIGSIZE])!=999);
213 return false;
214 }
215 void storeIndex(int loc, int fmt, int value) {
216 storeIndex(bytes, loc, fmt, value);
217 }
218 static
219 void storeIndex(byte[] bytes, int loc, int fmt, int value) {
220 switch (fmt) {
221 case U2_FORMAT:
222 assert(value == (value & 0xFFFF)) : (value);
223 bytes[loc+0] = (byte)(value >> 8);
224 bytes[loc+1] = (byte)(value >> 0);
225 break;
226 case U1_FORMAT:
227 assert(value == (value & 0xFF)) : (value);
228 bytes[loc] = (byte)value;
229 break;
230 default: assert(false);
231 }
232 }
233
234 /** Simple and necessary tuple to present each fixup. */
235 public static
236 class Fixup implements Comparable {
237 int desc; // location and format of reloc
238 Entry entry; // which entry to plug into the bytes
239 Fixup(int desc, Entry entry) {
240 this.desc = desc;
241 this.entry = entry;
242 }
243 public Fixup(int loc, int fmt, Entry entry) {
244 this.desc = makeDesc(loc, fmt);
245 this.entry = entry;
246 }
247 public int location() { return descLoc(desc); }
248 public int format() { return descFmt(desc); }
249 public Entry entry() { return entry; }
250 public int compareTo(Fixup that) {
251 // Ordering depends only on location.
252 return this.location() - that.location();
253 }
254 public int compareTo(Object that) {
255 return compareTo((Fixup)that);
256 }
257 public boolean equals(Object x) {
258 if (!(x instanceof Fixup)) return false;
259 Fixup that = (Fixup) x;
260 return this.desc == that.desc && this.entry == that.entry;
261 }
262 public String toString() {
263 return "@"+location()+(format()==U1_FORMAT?".1":"")+"="+entry;
264 }
265 }
266
267 private
268 class Itr implements Iterator {
269 int index = 0; // index into entries
270 int bigIndex = BIGSIZE+1; // index into bigDescs
271 int next = head; // desc pointing to next fixup
272 public boolean hasNext() { return index < size; }
273 public void remove() { throw new UnsupportedOperationException(); }
274 public Object next() {
275 int thisIndex = index;
276 return new Fixup(nextDesc(), entries[thisIndex]);
277 }
278 int nextDesc() {
279 int thisIndex = index++;
280 int thisDesc = next;
281 if (index < size) {
282 // Fetch next desc eagerly, in case this fixup gets finalized.
283 int loc = descLoc(thisDesc);
284 int fmt = descFmt(thisDesc);
285 if (bytes != null && bytes[loc] != OVERFLOW_BYTE) {
286 next = fetchDesc(loc, fmt);
287 } else {
288 // The unused extra byte is "asserted" to be equal to BI.
289 // This helps keep the overflow descs in sync.
290 assert(fmt==U1_FORMAT || bytes == null || bytes[loc+1]==(byte)bigIndex);
291 next = bigDescs[bigIndex++];
292 }
293 }
294 return thisDesc;
295 }
296 }
297
298 public Iterator iterator() {
299 return new Itr();
300 }
301 public void add(int location, int format, Entry entry) {
302 addDesc(makeDesc(location, format), entry);
303 }
304 public boolean add(Fixup f) {
305 addDesc(f.desc, f.entry);
306 return true;
307 }
308 public boolean add(Object fixup) {
309 return add((Fixup) fixup);
310 }
311 public boolean addAll(Collection c) {
312 if (c instanceof Fixups) {
313 // Use knowledge of Itr structure to avoid building little structs.
314 Fixups that = (Fixups) c;
315 if (that.size == 0) return false;
316 if (this.size == 0 && entries.length < that.size)
317 growEntries(that.size); // presize exactly
318 Entry[] thatEntries = that.entries;
319 for (Itr i = that.new Itr(); i.hasNext(); ) {
320 int ni = i.index;
321 addDesc(i.nextDesc(), thatEntries[ni]);
322 }
323 return true;
324 } else {
325 return super.addAll(c);
326 }
327 }
328 // Here is how things get added:
329 private void addDesc(int thisDesc, Entry entry) {
330 if (entries.length == size)
331 growEntries(size * 2);
332 entries[size] = entry;
333 if (size == 0) {
334 head = tail = thisDesc;
335 } else {
336 int prevDesc = tail;
337 // Store new desc in previous tail.
338 int prevLoc = descLoc(prevDesc);
339 int prevFmt = descFmt(prevDesc);
340 int prevLen = fmtLen(prevFmt);
341 int thisLoc = descLoc(thisDesc);
342 // The collection must go in ascending order, and not overlap.
343 if (thisLoc < prevLoc + prevLen)
344 badOverlap(thisLoc);
345 tail = thisDesc;
346 if (!storeDesc(prevLoc, prevFmt, thisDesc)) {
347 // overflow
348 int bigSize = bigDescs[BIGSIZE];
349 if (bigDescs.length == bigSize)
350 growBigDescs();
351 //System.out.println("bigDescs["+bigSize+"] = "+thisDesc);
352 bigDescs[bigSize++] = thisDesc;
353 bigDescs[BIGSIZE] = bigSize;
354 }
355 }
356 size += 1;
357 }
358 private void badOverlap(int thisLoc) {
359 throw new IllegalArgumentException("locs must be ascending and must not overlap: "+thisLoc+" >> "+this);
360 }
361
362 private void growEntries(int newSize) {
363 Entry[] oldEntries = entries;
364 entries = new Entry[Math.max(3, newSize)];
365 System.arraycopy(oldEntries, 0, entries, 0, oldEntries.length);
366 }
367 private void growBigDescs() {
368 int[] oldBigDescs = bigDescs;
369 bigDescs = new int[oldBigDescs.length * 2];
370 System.arraycopy(oldBigDescs, 0, bigDescs, 0, oldBigDescs.length);
371 }
372
373 /// Static methods that optimize the use of this class.
374 public static
375 Object add(Object prevFixups,
376 byte[] bytes, int loc, int fmt,
377 Entry e) {
378 Fixups f;
379 if (prevFixups == null) {
380 if (loc == SPECIAL_LOC && fmt == SPECIAL_FMT) {
381 // Special convention: If the attribute has a
382 // U2 relocation at position zero, store the Entry
383 // rather than building a Fixups structure.
384 return e;
385 }
386 f = new Fixups(bytes);
387 } else if (!(prevFixups instanceof Fixups)) {
388 // Recognize the special convention:
389 Entry firstEntry = (Entry) prevFixups;
390 f = new Fixups(bytes);
391 f.add(SPECIAL_LOC, SPECIAL_FMT, firstEntry);
392 } else {
393 f = (Fixups) prevFixups;
394 assert(f.bytes == bytes);
395 }
396 f.add(loc, fmt, e);
397 return f;
398 }
399
400 public static
401 void setBytes(Object fixups, byte[] bytes) {
402 if (fixups instanceof Fixups) {
403 Fixups f = (Fixups) fixups;
404 f.setBytes(bytes);
405 }
406 }
407
408 public static
409 Object trimToSize(Object fixups) {
410 if (fixups instanceof Fixups) {
411 Fixups f = (Fixups) fixups;
412 f.trimToSize();
413 if (f.size() == 0)
414 fixups = null;
415 }
416 return fixups;
417 }
418
419 // Iterate over all the references in this set of fixups.
420 public static
421 void visitRefs(Object fixups, Collection refs) {
422 if (fixups == null) {
423 } else if (!(fixups instanceof Fixups)) {
424 // Special convention; see above.
425 refs.add((Entry) fixups);
426 } else {
427 Fixups f = (Fixups) fixups;
428 f.visitRefs(refs);
429 }
430 }
431
432 // Clear out this set of fixups by replacing each reference
433 // by a hardcoded coding of its reference, drawn from ix.
434 public static
435 void finishRefs(Object fixups, byte[] bytes, ConstantPool.Index ix) {
436 if (fixups == null)
437 return;
438 if (!(fixups instanceof Fixups)) {
439 // Special convention; see above.
440 int index = ix.indexOf((Entry) fixups);
441 storeIndex(bytes, SPECIAL_LOC, SPECIAL_FMT, index);
442 return;
443 }
444 Fixups f = (Fixups) fixups;
445 assert(f.bytes == bytes);
446 f.finishRefs(ix);
447 }
448
449 void finishRefs(ConstantPool.Index ix) {
450 if (isEmpty())
451 return;
452 for (Iterator i = iterator(); i.hasNext(); ) {
453 Fixup fx = (Fixup) i.next();
454 int index = ix.indexOf(fx.entry);
455 //System.out.println("finish "+fx+" = "+index);
456 // Note that the iterator has already fetched the
457 // bytes we are about to overwrite.
458 storeIndex(fx.location(), fx.format(), index);
459 }
460 // Further iterations should do nothing:
461 bytes = null; // do not clean them
462 clear();
463 }
464
465/*
466 /// Testing.
467 public static void main(String[] av) {
468 byte[] bytes = new byte[1 << 20];
469 ConstantPool cp = new ConstantPool();
470 Fixups f = new Fixups(bytes);
471 boolean isU1 = false;
472 int span = 3;
473 int nextLoc = 0;
474 int[] locs = new int[100];
475 final int[] indexes = new int[100];
476 int iptr = 1;
477 for (int loc = 0; loc < bytes.length; loc++) {
478 if (loc == nextLoc && loc+1 < bytes.length) {
479 int fmt = (isU1 ? U1_FORMAT : U2_FORMAT);
480 Entry e = ConstantPool.getUtf8Entry("L"+loc);
481 f.add(loc, fmt, e);
482 isU1 ^= true;
483 if (iptr < 10) {
484 // Make it close in.
485 nextLoc += fmtLen(fmt) + (iptr < 5 ? 0 : 1);
486 } else {
487 nextLoc += span;
488 span = (int)(span * 1.77);
489 }
490 // Here are the bytes that would have gone here:
491 locs[iptr] = loc;
492 if (fmt == U1_FORMAT) {
493 indexes[iptr++] = (loc & 0xFF);
494 } else {
495 indexes[iptr++] = ((loc & 0xFF) << 8) | ((loc+1) & 0xFF);
496 ++loc; // skip a byte
497 }
498 continue;
499 }
500 bytes[loc] = (byte)loc;
501 }
502 System.out.println("size="+f.size()
503 +" overflow="+(f.bigDescs[BIGSIZE]-1));
504 System.out.println("Fixups: "+f);
505 // Test collection contents.
506 assert(iptr == 1+f.size());
507 List l = new ArrayList(f);
508 Collections.sort(l); // should not change the order
509 if (!l.equals(new ArrayList(f))) System.out.println("** disordered");
510 f.setBytes(null);
511 if (!l.equals(new ArrayList(f))) System.out.println("** bad set 1");
512 f.setBytes(bytes);
513 if (!l.equals(new ArrayList(f))) System.out.println("** bad set 2");
514 Fixups f3 = new Fixups(f);
515 if (!l.equals(new ArrayList(f3))) System.out.println("** bad set 3");
516 Iterator fi = f.iterator();
517 for (int i = 1; i < iptr; i++) {
518 Fixup fx = (Fixup) fi.next();
519 if (fx.location() != locs[i]) {
520 System.out.println("** "+fx+" != "+locs[i]);
521 }
522 if (fx.format() == U1_FORMAT)
523 System.out.println(fx+" -> "+bytes[locs[i]]);
524 else
525 System.out.println(fx+" -> "+bytes[locs[i]]+" "+bytes[locs[i]+1]);
526 }
527 assert(!fi.hasNext());
528 indexes[0] = 1; // like iptr
529 Index ix = new Index("ix") {
530 public int indexOf(Entry e) {
531 return indexes[indexes[0]++];
532 }
533 };
534 f.finishRefs(ix);
535 for (int loc = 0; loc < bytes.length; loc++) {
536 if (bytes[loc] != (byte)loc) {
537 System.out.println("** ["+loc+"] = "+bytes[loc]+" != "+(byte)loc);
538 }
539 }
540 }
541//*/
542}