import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Vector; /** * This class tries to produce a bug on the profiler that involves showing * impossible stacktraces. * *

It creates two different kind of lists, {@link List1} and {@link List2}, that * are each used and called in independent contexts and methods, such as any {@link List1} * method should never be seen in a stacktrace containing any methods with a 2 in it's name * and vice versa. * *

For example, the following stacktrace is impossible: *

 * java.lang.Integer.valueOf(Integer.java -- method id 0x7f552c0cf9e0:642)
 * com.qfs.profiler.test.NestedInterface$List1.writeInt(NestedInterface.java -- method id 0x7f552c154c70:400)
 * com.qfs.profiler.test.NestedInterface.transferSome(NestedInterface.java -- method id 0x7f552c167010:-1)
 * com.qfs.profiler.test.NestedInterface.transferOne(NestedInterface.java -- method id 0x7f552c166ff8:240)
 * com.qfs.profiler.test.NestedInterface.transferTwo(NestedInterface.java -- method id 0x7f552c166ff0:230)
 * com.qfs.profiler.test.NestedInterface.transferList(NestedInterface.java -- method id 0x7f552c166fe8:211)
 * com.qfs.profiler.test.NestedInterface.computeList2(NestedInterface.java -- method id 0x7f552c166fe0:204)
 * com.qfs.profiler.test.NestedInterface.runList2(NestedInterface.java -- method id 0x7f552c166fc0:168)
 * com.qfs.profiler.test.NestedInterface.doDummyWork(NestedInterface.java -- method id 0x7f552c166fa0:40)
 * com.qfs.profiler.test.NestedInterface.main(NestedInterface.java -- method id 0x7f552c166f98:24)
 * 
*/ public class NestedInterface { public static void main(String[] args) { doDummyWork(); } /** * Does some work to test the profiler. */ public static void doDummyWork() { final int nbEls = 1<<25; final int nbRuns = 1<<0; //Lets do a bunch of computation, so a bug //is more likely to appear. final int nbComputations = 1<<6; runList1(nbEls, nbRuns, nbComputations); System.out.println(""); System.out.println("============================="); System.out.println("Start second computing phase."); System.out.println("============================="); System.out.println(""); runList2(nbEls, nbRuns, nbComputations); } /** * Do computations on the two lists in a mixed way. * * @param nbEls the number of elements to store in a custom list * @param nbRuns the number of time to run the method * @param nbComputations the number of time to do core computation (transfering the data * from an {@link ArrayList} to both {@link List1} and {@link List2}). */ public static void runList1AndList2(final int nbEls, final int nbRuns, final int nbComputations) { for(int run=0; run sourceList = new ArrayList<>(); for (int i=0; i sourceList = new ArrayList<>(); for (int i=0; i sourceList = new ArrayList<>(); for (int i=0; i source, IWritableNumberList dest) { transferList(source, dest); } /** * Do some computing. (Transfer the source to dest) * * @param source the source list * @param dest the destination list */ public static void computeList2(ArrayList source, IWritableNumberList dest) { transferList(source, dest); } /** * Transfer the data of source list to dest list by batches of two. * No checks are made on the sizes of the lists. * * @param source the source list * @param dest the destination list */ public static void transferList(ArrayList source, IWritableNumberList dest) { int i=0; for (; i This method is here to provide an alternative to the {@link #transferList(ArrayList, IWritableNumberList)} * method and allow having different stacktraces. * * @param source the source list * @param dest the destination list */ public static void reverseTransferList(ArrayList source, IWritableNumberList dest) { int i=source.size()-1; for (; i>0 ; i-=2) { reverseTransferTwo(source, dest, i); } if(i==0) { transferOne(source, dest, i); } } /** * Transfer two records in ascending order, starting from idx. * @param source * @param dest * @param idx the index of the records to transfer */ public static void transferTwo(ArrayList source, IWritableNumberList dest, int idx) { transferOne(source, dest, idx); transferOne(source, dest, idx+1); } /** * Transfer two records in descending order, starting from idx. * * @param source * @param dest * @param idx the index of the records to transfer */ public static void reverseTransferTwo(ArrayList source, IWritableNumberList dest, int idx) { transferOne(source, dest, idx); transferOne(source, dest, idx-1); } /** * Transfer one record from the source list to the dest list. * * @param source * @param dest * @param idx the index of the records to transfer */ public static void transferOne(ArrayList source, IWritableList dest, int idx) { //To add some depth to the stack trace, we call yet another function. transferSome(source,dest, idx, idx+1); } /** * Transfer a batch of records from source list to dest list. * @param source * @param dest * @param startIdx the index, inclusive, at which to start transferring. * @param endIdx the index, exclusive, at which to end transferring. */ public static void transferSome(ArrayList source, IWritableList dest, int startIdx, int endIdx) { for (int i=startIdx; i */ protected static interface INumberList extends IList, Iterable{ int size(); } /** * An interface for a read-write list able to store some {@link Number numbers}. * * @param */ public static interface IWritableNumberList extends INumberList, IWritableList { /** * Make sure the list can hold capacity items. * @param capacity */ void ensureCapacity(int capacity); /** * Empty the list of any content. */ void clear(); } /** * Abstract implementation of an {@link INumberList}. */ protected abstract static class ANumberList implements INumberList { final List underlying; long counter = 0; public ANumberList(List underlying) { this.underlying = underlying; } public int size() { return underlying.size(); } } /** * First implementation of an {@link ANumberList}, for testing purposes. */ protected static class List1 extends ANumberList implements IWritableNumberList { public List1() { super(new Vector()); } @Override public Object read(int idx) { return underlying.get(idx); } @Override public int readInt(int idx) { return underlying.get(idx); } @Override public long readLong(int idx) { return underlying.get(idx); } @Override public Iterator iterator() { return underlying.iterator(); } @Override public void write(int idx, Object value) { underlying.set(idx, (Integer)value); } @Override public void add(Object value) { underlying.add((Integer)value); } @Override public void writeInt(int idx, int value) { underlying.set(idx, value); } @Override public void addInt(int value) { underlying.add(value); } @Override public void writeLong(int idx, long value) { throw new UnsupportedOperationException("Cannot write a long in an integer list."); } @Override public void addLong(long value) { throw new UnsupportedOperationException("Cannot write a long in an integer list."); } @Override public void ensureCapacity(int capacity) { ((Vector)underlying).ensureCapacity(capacity); } @Override public void clear() { underlying.clear(); } } /** * A dummy interface, to complexify the structure. */ protected static interface IDummyTable2 extends IList{ int dummyTable2(); } /** * A dummy interface, to complexify the structure. */ protected static interface IList2 extends IDummyTable2, IWritableList { int list2(); } /** * Second implementation of an {@link ANumberList}, for testing purposes. */ protected static class List2 extends ANumberList implements IWritableNumberList, IList2{ public List2() { super(new ArrayList()); } @Override public Object read(int idx) { return underlying.get(idx); } @Override public int readInt(int idx) { return underlying.get(idx); } @Override public long readLong(int idx) { return underlying.get(idx); } @Override public Iterator iterator() { return underlying.iterator(); } @Override public void write(int idx, Object value) { underlying.set(idx, (Integer)value); } @Override public void add(Object value) { underlying.add((Integer)value); } @Override public void writeInt(int idx, int value) { underlying.set(idx, value); } @Override public void addInt(int value) { underlying.add(value); } @Override public void writeLong(int idx, long value) { throw new UnsupportedOperationException("Cannot write a long in an integer list."); } @Override public void addLong(long value) { throw new UnsupportedOperationException("Cannot write a long in an integer list."); } @Override public void ensureCapacity(int capacity) { ((ArrayList)underlying).ensureCapacity(capacity); } @Override public void clear() { underlying.clear(); } @Override public int dummyTable2() { return 0; } @Override public int list2() { return 0; } } }