comparison test/compiler/6865031/Test.java @ 899:55cb84cd1247

6865031: Application gives bad result (throws bad exception) with compressed oops Summary: Produce narrow type for new Phi from the original Phi type. Reviewed-by: cfang
author kvn
date Fri, 31 Jul 2009 12:04:07 -0700
parents
children 9a4e87ba1a90
comparison
equal deleted inserted replaced
898:60fea60a6db5 899:55cb84cd1247
1 /*
2 * Copyright 2009 Goldman Sachs International. 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
24
25 /*
26 * @test
27 * @bug 6865031
28 * @summary Application gives bad result (throws bad exception) with compressed oops
29 * @run main/othervm -XX:+UseCompressedOops -XX:HeapBaseMinAddress=32g -XX:-LoopUnswitching -XX:CompileCommand=inline,AbstractMemoryEfficientList.equals Test hello goodbye
30 */
31
32 import java.lang.ref.ReferenceQueue;
33 import java.lang.ref.WeakReference;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.List;
37
38 interface MyList {
39 public int size();
40 public Object set(final int index, final Object element);
41 public Object get(final int index);
42 }
43
44 abstract class AbstractMemoryEfficientList implements MyList {
45 abstract public int size();
46 abstract public Object get(final int index);
47 abstract public Object set(final int index, final Object element);
48
49 public boolean equals(Object o) {
50 if (o == this) {
51 return true;
52 }
53
54 if (!(o instanceof MyList)) {
55 return false;
56 }
57
58 final MyList that = (MyList) o;
59 if (this.size() != that.size()) {
60 return false;
61 }
62
63 for (int i = 0; i < this.size(); i++) {
64 try {
65 if (!((this.get(i)).equals(that.get(i)))) {
66 return false;
67 }
68 } catch (IndexOutOfBoundsException e) {
69 System.out.println("THROWING RT EXC");
70 System.out.println("concurrent modification of this:" + this.getClass() + ":" + System.identityHashCode(this) + "; that:" + that.getClass() + ":" + System.identityHashCode(that) + "; i:" + i);
71 e.printStackTrace();
72 System.exit(97);
73 throw new RuntimeException("concurrent modification of this:" + this.getClass() + ":" + System.identityHashCode(this) + "; that:" + that.getClass() + ":" + System.identityHashCode(that) + "; i:" + i, e);
74 }
75 }
76 return true;
77 }
78
79 public int hashCode() {
80 int hashCode = 1;
81 for (int i = 0; i < this.size(); i++) {
82 Object obj = this.get(i);
83 hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
84 }
85 return hashCode;
86 }
87 }
88
89 final class SingletonList extends AbstractMemoryEfficientList {
90 private Object element1;
91
92 SingletonList(final Object obj1) {
93 super();
94 this.element1 = obj1;
95 }
96
97 public int size() {
98 return 1;
99 }
100
101 public Object get(final int index) {
102 if (index == 0) {
103 return this.element1;
104 } else {
105 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size());
106 }
107 }
108
109 public Object set(final int index, final Object element) {
110 if (index == 0) {
111 final Object previousElement = this.element1;
112 this.element1 = element;
113 return previousElement;
114 } else {
115 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size());
116 }
117 }
118 }
119
120 final class DoubletonList extends AbstractMemoryEfficientList {
121 private Object element1;
122 private Object element2;
123
124 DoubletonList(final Object obj1, final Object obj2) {
125 this.element1 = obj1;
126 this.element2 = obj2;
127 }
128
129 public int size() {
130 return 2;
131 }
132
133 public Object get(final int index) {
134 switch (index) {
135 case 0 : return this.element1;
136 case 1 : return this.element2;
137 default: throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size());
138 }
139 }
140
141 public Object set(final int index, final Object element) {
142 switch (index) {
143 case 0 :
144 {
145 final Object previousElement = this.element1;
146 this.element1 = element;
147 return previousElement;
148 }
149 case 1 :
150 {
151 final Object previousElement = this.element2;
152 this.element2 = element;
153 return previousElement;
154 }
155 default : throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size());
156 }
157 }
158 }
159
160 class WeakPool<V> {
161 protected static final int DEFAULT_INITIAL_CAPACITY = 16;
162 private static final int MAXIMUM_CAPACITY = 1 << 30;
163 private static final float DEFAULT_LOAD_FACTOR = 0.75f;
164
165 protected Entry<V>[] table;
166
167 private int size;
168 protected int threshold;
169 private final float loadFactor;
170 private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
171
172 public WeakPool()
173 {
174 this.loadFactor = DEFAULT_LOAD_FACTOR;
175 threshold = DEFAULT_INITIAL_CAPACITY;
176 table = new Entry[DEFAULT_INITIAL_CAPACITY];
177 }
178
179 /**
180 * Check for equality of non-null reference x and possibly-null y. By
181 * default uses Object.equals.
182 */
183 private boolean eq(Object x, Object y)
184 {
185 return x == y || x.equals(y);
186 }
187
188 /**
189 * Return index for hash code h.
190 */
191 private int indexFor(int h, int length)
192 {
193 return h & length - 1;
194 }
195
196 /**
197 * Expunge stale entries from the table.
198 */
199 private void expungeStaleEntries()
200 {
201 Object r;
202 while ((r = queue.poll()) != null)
203 {
204 Entry e = (Entry) r;
205 int h = e.hash;
206 int i = indexFor(h, table.length);
207
208 // System.out.println("EXPUNGING " + h);
209 Entry<V> prev = table[i];
210 Entry<V> p = prev;
211 while (p != null)
212 {
213 Entry<V> next = p.next;
214 if (p == e)
215 {
216 if (prev == e)
217 {
218 table[i] = next;
219 }
220 else
221 {
222 prev.next = next;
223 }
224 e.next = null; // Help GC
225 size--;
226 break;
227 }
228 prev = p;
229 p = next;
230 }
231 }
232 }
233
234 /**
235 * Return the table after first expunging stale entries
236 */
237 private Entry<V>[] getTable()
238 {
239 expungeStaleEntries();
240 return table;
241 }
242
243 /**
244 * Returns the number of key-value mappings in this map.
245 * This result is a snapshot, and may not reflect unprocessed
246 * entries that will be removed before next attempted access
247 * because they are no longer referenced.
248 */
249 public int size()
250 {
251 if (size == 0)
252 {
253 return 0;
254 }
255 expungeStaleEntries();
256 return size;
257 }
258
259 /**
260 * Returns <tt>true</tt> if this map contains no key-value mappings.
261 * This result is a snapshot, and may not reflect unprocessed
262 * entries that will be removed before next attempted access
263 * because they are no longer referenced.
264 */
265 public boolean isEmpty()
266 {
267 return size() == 0;
268 }
269
270 /**
271 * Returns the value stored in the pool that equals the requested key
272 * or <tt>null</tt> if the map contains no mapping for
273 * this key (or the key is null)
274 *
275 * @param key the key whose equals value is to be returned.
276 * @return the object that is equal the specified key, or
277 * <tt>null</tt> if key is null or no object in the pool equals the key.
278 */
279 public V get(V key)
280 {
281 if (key == null)
282 {
283 return null;
284 }
285 int h = key.hashCode();
286 Entry<V>[] tab = getTable();
287 int index = indexFor(h, tab.length);
288 Entry<V> e = tab[index];
289 while (e != null)
290 {
291 V candidate = e.get();
292 if (e.hash == h && eq(key, candidate))
293 {
294 return candidate;
295 }
296 e = e.next;
297 }
298 return null;
299 }
300
301 /**
302 * Returns the entry associated with the specified key in the HashMap.
303 * Returns null if the HashMap contains no mapping for this key.
304 */
305 Entry getEntry(Object key)
306 {
307 int h = key.hashCode();
308 Entry[] tab = getTable();
309 int index = indexFor(h, tab.length);
310 Entry e = tab[index];
311 while (e != null && !(e.hash == h && eq(key, e.get())))
312 {
313 e = e.next;
314 }
315 return e;
316 }
317
318 /**
319 * Places the object into the pool. If the object is null, nothing happens.
320 * If an equal object already exists, it is not replaced.
321 *
322 * @param key the object to put into the pool. key may be null.
323 * @return the object in the pool that is equal to the key, or the newly placed key if no such object existed when put was called
324 */
325 public V put(V key)
326 {
327 if (key == null)
328 {
329 return null;
330 }
331 int h = key.hashCode();
332 Entry<V>[] tab = getTable();
333 int i = indexFor(h, tab.length);
334
335 for (Entry<V> e = tab[i]; e != null; e = e.next)
336 {
337 V candidate = e.get();
338 if (h == e.hash && eq(key, candidate))
339 {
340 return candidate;
341 }
342 }
343
344 tab[i] = new Entry<V>(key, queue, h, tab[i]);
345
346 if (++size >= threshold)
347 {
348 resize(tab.length * 2);
349 }
350
351 // System.out.println("Added " + key + " to pool");
352 return key;
353 }
354
355 /**
356 * Rehashes the contents of this map into a new array with a
357 * larger capacity. This method is called automatically when the
358 * number of keys in this map reaches its threshold.
359 * <p/>
360 * If current capacity is MAXIMUM_CAPACITY, this method does not
361 * resize the map, but but sets threshold to Integer.MAX_VALUE.
362 * This has the effect of preventing future calls.
363 *
364 * @param newCapacity the new capacity, MUST be a power of two;
365 * must be greater than current capacity unless current
366 * capacity is MAXIMUM_CAPACITY (in which case value
367 * is irrelevant).
368 */
369 void resize(int newCapacity)
370 {
371 Entry<V>[] oldTable = getTable();
372 int oldCapacity = oldTable.length;
373 if (oldCapacity == MAXIMUM_CAPACITY)
374 {
375 threshold = Integer.MAX_VALUE;
376 return;
377 }
378
379 Entry<V>[] newTable = new Entry[newCapacity];
380 transfer(oldTable, newTable);
381 table = newTable;
382
383 /*
384 * If ignoring null elements and processing ref queue caused massive
385 * shrinkage, then restore old table. This should be rare, but avoids
386 * unbounded expansion of garbage-filled tables.
387 */
388 if (size >= threshold / 2)
389 {
390 threshold = (int) (newCapacity * loadFactor);
391 }
392 else
393 {
394 expungeStaleEntries();
395 transfer(newTable, oldTable);
396 table = oldTable;
397 }
398 }
399
400 /**
401 * Transfer all entries from src to dest tables
402 */
403 private void transfer(Entry[] src, Entry[] dest)
404 {
405 for (int j = 0; j < src.length; ++j)
406 {
407 Entry e = src[j];
408 src[j] = null;
409 while (e != null)
410 {
411 Entry next = e.next;
412 Object key = e.get();
413 if (key == null)
414 {
415 e.next = null; // Help GC
416 size--;
417 }
418 else
419 {
420 int i = indexFor(e.hash, dest.length);
421 e.next = dest[i];
422 dest[i] = e;
423 }
424 e = next;
425 }
426 }
427 }
428
429 /**
430 * Removes the object in the pool that equals the key.
431 *
432 * @param key
433 * @return previous value associated with specified key, or <tt>null</tt>
434 * if there was no mapping for key or the key is null.
435 */
436 public V removeFromPool(V key)
437 {
438 if (key == null)
439 {
440 return null;
441 }
442 int h = key.hashCode();
443 Entry<V>[] tab = getTable();
444 int i = indexFor(h, tab.length);
445 Entry<V> prev = tab[i];
446 Entry<V> e = prev;
447
448 while (e != null)
449 {
450 Entry<V> next = e.next;
451 V candidate = e.get();
452 if (h == e.hash && eq(key, candidate))
453 {
454 size--;
455 if (prev == e)
456 {
457 tab[i] = next;
458 }
459 else
460 {
461 prev.next = next;
462 }
463 return candidate;
464 }
465 prev = e;
466 e = next;
467 }
468
469 return null;
470 }
471
472 /**
473 * Removes all mappings from this map.
474 */
475 public void clear()
476 {
477 // clear out ref queue. We don't need to expunge entries
478 // since table is getting cleared.
479 while (queue.poll() != null)
480 {
481 // nop
482 }
483
484 table = new Entry[DEFAULT_INITIAL_CAPACITY];
485 threshold = DEFAULT_INITIAL_CAPACITY;
486 size = 0;
487
488 // Allocation of array may have caused GC, which may have caused
489 // additional entries to go stale. Removing these entries from the
490 // reference queue will make them eligible for reclamation.
491 while (queue.poll() != null)
492 {
493 // nop
494 }
495 }
496
497 /**
498 * The entries in this hash table extend WeakReference, using its main ref
499 * field as the key.
500 */
501 protected static class Entry<V>
502 extends WeakReference<V>
503 {
504 private final int hash;
505 private Entry<V> next;
506
507 /**
508 * Create new entry.
509 */
510 Entry(final V key, final ReferenceQueue<V> queue, final int hash, final Entry<V> next)
511 {
512 super(key, queue);
513 this.hash = hash;
514 this.next = next;
515 }
516
517 public V getKey()
518 {
519 return super.get();
520 }
521
522 public boolean equals(Object o)
523 {
524 if (!(o instanceof WeakPool.Entry))
525 {
526 return false;
527 }
528 WeakPool.Entry<V> that = (WeakPool.Entry<V>) o;
529 V k1 = this.getKey();
530 V k2 = that.getKey();
531 return (k1==k2 || k1.equals(k2));
532 }
533
534 public int hashCode()
535 {
536 return this.hash;
537 }
538
539 public String toString()
540 {
541 return String.valueOf(this.getKey());
542 }
543 }
544 }
545
546 final class MultiSynonymKey {
547 private List<MyList> keys;
548
549 public MultiSynonymKey() {
550 keys = new ArrayList<MyList>();
551 }
552
553 public MultiSynonymKey(MyList... arg) {
554 keys = Arrays.asList(arg);
555 }
556
557 public List<MyList> getKeys() {
558 return keys;
559 }
560
561 public int hashCode() {
562 return this.getKeys().hashCode();
563 }
564
565 public boolean equals(Object obj) {
566 if (this == obj) {
567 return true;
568 }
569
570 if (!(obj instanceof MultiSynonymKey)) {
571 return false;
572 }
573
574 MultiSynonymKey that = (MultiSynonymKey) obj;
575 return this.getKeys().equals(that.getKeys());
576 }
577
578 public String toString() {
579 return this.getClass().getName() + this.getKeys().toString();
580 }
581 }
582
583 public class Test extends Thread {
584 static public Test test;
585 static private byte[] arg1;
586 static private byte[] arg2;
587 static public WeakPool<MultiSynonymKey> wp;
588 public volatile MultiSynonymKey ml1;
589 public volatile MultiSynonymKey ml2;
590 private volatile MultiSynonymKey ml3;
591
592 public void run() {
593 int count=0;
594 while (true) {
595 try {
596 Thread.sleep(10);
597 } catch (Exception e) {}
598 synchronized (wp) {
599 ml2 = new MultiSynonymKey(new DoubletonList(new String(arg1), new String(arg2)));
600 wp.put(ml2);
601 ml3 = new MultiSynonymKey(new DoubletonList(new String(arg1), new String(arg2)));
602 }
603 try {
604 Thread.sleep(10);
605 } catch (Exception e) {}
606 synchronized (wp) {
607 ml1 = new MultiSynonymKey(new SingletonList(new String(arg1)));
608 wp.put(ml1);
609 ml3 = new MultiSynonymKey(new SingletonList(new String(arg1)));
610 }
611 if (count++==100)
612 System.exit(95);
613 }
614 }
615
616 public static void main(String[] args) throws Exception {
617 wp = new WeakPool<MultiSynonymKey>();
618 test = new Test();
619
620 test.arg1 = args[0].getBytes();
621 test.arg2 = args[1].getBytes();
622
623 test.ml1 = new MultiSynonymKey(new SingletonList(new String(test.arg1)));
624 test.ml2 = new MultiSynonymKey(new DoubletonList(new String(test.arg1), new String(test.arg2)));
625 test.ml3 = new MultiSynonymKey(new DoubletonList(new String(test.arg1), new String(test.arg2)));
626
627 wp.put(test.ml1);
628 wp.put(test.ml2);
629
630 test.setDaemon(true);
631 test.start();
632
633 int counter = 0;
634 while (true) {
635 synchronized (wp) {
636 MultiSynonymKey foo = test.ml3;
637
638 if (wp.put(foo) == foo) {
639 // System.out.println("foo " + counter);
640 // System.out.println(foo);
641 }
642 }
643 counter++;
644 }
645 }
646
647 private boolean eq(Object x, Object y) {
648 return x == y || x.equals(y);
649 }
650 }