8166790: Add stress test GCBasher
authorehelin
Thu, 06 Oct 2016 16:32:46 +0200 (2016-10-06)
changeset 42016 4ef693df9ff9
parent 42015 96e272c73d4a
child 42019 3755a8d3b514
8166790: Add stress test GCBasher Reviewed-by: dfazunen, dholmes, erikj, tschatzl, lmesnik
hotspot/test/TEST.groups
hotspot/test/gc/stress/gcbasher/ByteCursor.java
hotspot/test/gc/stress/gcbasher/Bytecode.java
hotspot/test/gc/stress/gcbasher/ClassInfo.java
hotspot/test/gc/stress/gcbasher/ConstantPoolEntry.java
hotspot/test/gc/stress/gcbasher/Decompiler.java
hotspot/test/gc/stress/gcbasher/Dependency.java
hotspot/test/gc/stress/gcbasher/MethodInfo.java
hotspot/test/gc/stress/gcbasher/TestGCBasher.java
hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java
hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java
hotspot/test/gc/stress/gcbasher/TestGCBasherWithParallel.java
hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java
--- a/hotspot/test/TEST.groups	Mon Oct 17 05:44:43 2016 -0700
+++ b/hotspot/test/TEST.groups	Thu Oct 06 16:32:46 2016 +0200
@@ -349,6 +349,12 @@
 hotspot_fast_gc_gcold = \
   gc/stress/TestGCOld.java
 
+hotspot_fast_gc_gcbasher = \
+  gc/stress/gcbasher/TestGCBasherWithG1.java \
+  gc/stress/gcbasher/TestGCBasherWithCMS.java \
+  gc/stress/gcbasher/TestGCBasherWithSerial.java \
+  gc/stress/gcbasher/TestGCBasherWithParallel.java
+
 hotspot_fast_runtime = \
   runtime/ \
  -runtime/6626217/Test6626217.sh \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/ByteCursor.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+class ByteCursor {
+    private int offset;
+    private byte[] data;
+
+    public ByteCursor(byte[] data) {
+        this.offset = 0;
+        this.data = data;
+    }
+
+    public int getOffset() {
+        return offset;
+    }
+
+    public void skipBytes(int n) {
+        offset += n;
+    }
+
+    public int readUnsignedByte() {
+        int val = readUnsignedByteAt(offset);
+        offset += 1;
+        return val;
+    }
+
+    public int readUnsignedByteAt(int offset) {
+        return data[offset++] & 0xff;
+    }
+
+    public int readUnsignedShort() {
+        int val = readUnsignedShortAt(offset);
+        offset += 2;
+        return val;
+    }
+
+    public int readInt() {
+        int val = readIntAt(offset);
+        offset += 4;
+        return val;
+    }
+
+    public int readUnsignedShortAt(int offset) {
+        int b1 = data[offset++] & 0xff;
+        int b2 = data[offset] & 0xff;
+
+        return (b1 << 8) + b2;
+    }
+
+    public int readIntAt(int offset) {
+        int s1 = readUnsignedShortAt(offset);
+        int s2 = readUnsignedShortAt(offset + 2);
+        return (s1 << 16) + s2;
+    }
+
+    public String readUtf8(int length) throws IllegalStateException {
+        char str[] = new char[length];
+        int count = 0;
+        int pos = 0;
+        while (count < length) {
+            int c = readUnsignedByte();
+            switch (c >> 4) {
+                case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: {
+                    // 0xxxxxxx
+                    count++;
+                    if(c == '/') {
+                        str[pos++] = '.';
+                    } else {
+                        str[pos++] = (char) c;
+                    }
+                    break;
+                } case 12: case 13: {
+                    // 110x xxxx   10xx xxxx
+                    count += 2;
+                    int c2 = readUnsignedByte();
+                    if ((c2 & 0xC0) != 0x80) {
+                        throw new IllegalStateException();
+                    }
+                    str[pos++] = (char) (((c & 0x1F) << 6) | (c2 & 0x3F));
+                    break;
+                } case 14: {
+                    // 1110 xxxx  10xx xxxx  10xx xxxx
+                    count += 3;
+                    int c2 = readUnsignedByte();
+                    int c3 = readUnsignedByte();
+                    if ((c2 & 0xC0) != 0x80 || (c3 & 0xC0) != 0x80) {
+                        throw new IllegalStateException();
+                    }
+                    str[pos++] = (char)(((c  & 0x0F) << 12) |
+                                        ((c2 & 0x3F) << 6)  |
+                                        ((c3 & 0x3F) << 0));
+                    break;
+                } default:
+                    // 10xx xxxx,  1111 xxxx
+                    throw new IllegalStateException();
+            }
+        }
+        return new String(str);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/Bytecode.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+class Bytecode {
+    public static final int IINC               = 132;
+    public static final int TABLESWITCH        = 170;
+    public static final int LOOKUPSWITCH       = 171;
+    public static final int GETSTATIC          = 178;
+    public static final int PUTSTATIC          = 179;
+    public static final int GETFIELD           = 180;
+    public static final int PUTFIELD           = 181;
+    public static final int INVOKEVIRTUAL      = 182;
+    public static final int INVOKESPECIAL      = 183;
+    public static final int INVOKESTATIC       = 184;
+    public static final int INVOKEINTERFACE    = 185;
+    public static final int NEW                = 187;
+    public static final int ANEWARRAY          = 189;
+    public static final int CHECKCAST          = 192;
+    public static final int INSTANCEOF         = 193;
+    public static final int MULTIANEWARRAY     = 197;
+    public static final int WIDE               = 196;
+
+    private static final int lengths[] = {
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        2,
+        3,
+        2,
+        3,
+        3,
+        2,
+        2,
+        2,
+        2,
+        2,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        2,
+        2,
+        2,
+        2,
+        2,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        3,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        2,
+        99,
+        99,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        3,
+        5,
+        5,
+        3,
+        2,
+        3,
+        1,
+        1,
+        3,
+        3,
+        1,
+        1,
+        0,
+        4,
+        3,
+        3,
+        5,
+        5,
+        1
+    };
+
+    public static int getLength(int bc) throws IllegalArgumentException {
+        if ((bc < 0) || (bc >= lengths.length)) {
+            throw new IllegalArgumentException("Unknown bytecode " + bc);
+        }
+        return lengths[bc];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/ClassInfo.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.util.HashSet;
+import java.util.Set;
+
+class ClassInfo {
+    private String name;
+
+    private Set<Dependency> staticResolution;
+    private Set<Dependency> staticInitialization;
+    private Set<Dependency> constructorResolution;
+    private Set<Dependency> constructorInitialization;
+    private Set<Dependency> methodResolution;
+    private Set<Dependency> methodInitialization;
+
+    public ClassInfo(String name) {
+        this.name = name;
+
+        staticResolution = new HashSet<>();
+        staticInitialization = new HashSet<>();
+        constructorResolution = new HashSet<>();
+        constructorInitialization = new HashSet<>();
+        methodResolution = new HashSet<>();
+        methodInitialization = new HashSet<>();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void addResolutionDep(Dependency d) {
+        if(d.getMethodName().equals("<clinit>")) {
+            staticResolution.add(d);
+        } else if(d.getMethodName().equals("<init>")) {
+            constructorResolution.add(d);
+        } else {
+            methodResolution.add(d);
+        }
+    }
+
+    public void addInitializationDep(Dependency d) {
+        if(d.getMethodName().equals("<clinit>")) {
+            staticInitialization.add(d);
+        } else if(d.getMethodName().equals("<init>")) {
+            constructorInitialization.add(d);
+        } else {
+            methodInitialization.add(d);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/ConstantPoolEntry.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+class ConstantPoolEntry {
+    private int index;
+    private String value;
+
+    public ConstantPoolEntry(int index) {
+        this.index = index;
+        value = null;
+    }
+
+    public ConstantPoolEntry(String value) {
+        this.index = -1;
+        this.value = value;
+    }
+
+    public String getValue() throws IllegalStateException {
+        if (index != -1) {
+            throw new IllegalStateException();
+        }
+        return value;
+    }
+
+    public int getNameIndex() throws IllegalStateException {
+        if (value != null) {
+            throw new IllegalStateException();
+        }
+        return index;
+    }
+
+    public int getClassIndex() throws IllegalStateException {
+        if (value != null) {
+            throw new IllegalStateException();
+        }
+        return index;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/Decompiler.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+class Decompiler {
+    private ByteCursor cursor;
+    private ClassInfo ci;
+
+    public Decompiler(byte[] classData) {
+        cursor = new ByteCursor(classData);
+
+        int magicNumber = cursor.readInt();
+        if (magicNumber != 0xCAFEBABE) {
+            throw new IllegalArgumentException("Bad magic number " + magicNumber);
+        }
+
+        cursor.readUnsignedShort(); // Minor version
+        cursor.readUnsignedShort(); // Major version
+
+        ConstantPoolEntry[] constantPool = decodeConstantPool();
+
+        cursor.readUnsignedShort(); // Access flags
+
+        // this class index in constant pool;
+        int classInfo = cursor.readUnsignedShort();
+        int classInfoNameIndex = constantPool[classInfo].getNameIndex();
+        ci = new ClassInfo(constantPool[classInfoNameIndex].getValue());
+
+        cursor.readUnsignedShort(); // superclass
+
+        int numInterfaces = cursor.readUnsignedShort();
+        for (int i = 0; i < numInterfaces; i++) {
+            cursor.readUnsignedShort(); // interface
+        }
+
+        decodeFields();
+        MethodInfo[] methods = decodeMethods(constantPool);
+        decodeMethodDependencies(methods, constantPool);
+    }
+
+    public ClassInfo getClassInfo() {
+        return ci;
+    }
+
+    private boolean isDependency(String name, String className) {
+        return !name.equals(className) && !name.startsWith("[");
+    }
+
+    private void addDependency(MethodInfo m, String name) {
+        Dependency d = new Dependency(m.getName(), m.getDescriptor(), name);
+        ci.addResolutionDep(d);
+    }
+
+    private String resolveName(ConstantPoolEntry[] constantPool, int cpi) {
+        int nameIndex = constantPool[cpi].getNameIndex();
+        return constantPool[nameIndex].getValue();
+    }
+
+    private void decodeMethodDependencies(MethodInfo[] methods, ConstantPoolEntry[] constantPool) {
+        for (int i = 0; i < methods.length; i++) {
+            MethodInfo m = methods[i];
+            final int stopCheck = m.getCodeStart() + m.getCodeLength();
+
+            int byteCodeIndex = m.getCodeStart();
+            while (byteCodeIndex < stopCheck) {
+                int bc = cursor.readUnsignedByteAt(byteCodeIndex);
+
+                switch (bc) {
+                    // These opcodes cause name resolution or initialization
+                    // Their index bytes all point to a CONSTANT_Class (4.4.1)
+                    case Bytecode.ANEWARRAY:
+                    case Bytecode.CHECKCAST:
+                    case Bytecode.INSTANCEOF:
+                    case Bytecode.MULTIANEWARRAY:
+                    case Bytecode.NEW: {
+                        int cpi = cursor.readUnsignedShortAt(byteCodeIndex + 1);
+                        String name = resolveName(constantPool, cpi);
+
+                        if (isDependency(name, ci.getName())) {
+                            addDependency(m, name);
+                        }
+                        break;
+                    }
+
+                    // These opcodes cause name resolution or initialization
+                    // Their index bytes all point to a CONSTANT_Field/Methodref (4.4.2)
+                    case Bytecode.GETFIELD:
+                    case Bytecode.INVOKEINTERFACE:
+                    case Bytecode.INVOKESPECIAL:
+                    case Bytecode.INVOKEVIRTUAL:
+                    case Bytecode.PUTFIELD:
+                    case Bytecode.PUTSTATIC:
+                    case Bytecode.GETSTATIC:
+                    case Bytecode.INVOKESTATIC: {
+                        int cpi = cursor.readUnsignedShortAt(byteCodeIndex + 1);
+                        int classIndex = constantPool[cpi].getClassIndex();
+                        String name = resolveName(constantPool, classIndex);
+
+                        if (isDependency(name, ci.getName())) {
+                            addDependency(m, name);
+                        }
+                        break;
+                    }
+
+                    case Bytecode.LOOKUPSWITCH: {
+                        byteCodeIndex++;
+                        int offset = byteCodeIndex - m.getCodeStart();
+                        while (offset % 4 != 0) {
+                            offset++;
+                            byteCodeIndex++;
+                        }
+
+                        int def = cursor.readIntAt(byteCodeIndex);
+                        byteCodeIndex +=4;
+
+                        int npairs = cursor.readIntAt(byteCodeIndex);
+                        byteCodeIndex +=4;
+                        byteCodeIndex += (8 * npairs);
+                        continue;
+                    }
+
+                    case Bytecode.TABLESWITCH: {
+                        byteCodeIndex++;
+                        int offset = byteCodeIndex - m.getCodeStart();
+                        while (offset % 4 != 0) {
+                            offset++;
+                            byteCodeIndex++;
+                        }
+
+                        int def = cursor.readIntAt(byteCodeIndex);
+                        byteCodeIndex +=4;
+
+                        int low = cursor.readIntAt(byteCodeIndex);
+                        byteCodeIndex +=4;
+                        int high = cursor.readIntAt(byteCodeIndex);
+                        byteCodeIndex +=4;
+                        byteCodeIndex += (4 * (high - low + 1));
+                        continue;
+                    }
+
+                    case Bytecode.WIDE: {
+                        bc = cursor.readUnsignedByteAt(++byteCodeIndex);
+                        if (bc == Bytecode.IINC) {
+                            byteCodeIndex += 5;
+                        } else {
+                            byteCodeIndex += 3;
+                        }
+                        continue;
+                    }
+                }
+
+                byteCodeIndex += Bytecode.getLength(bc);
+            }
+
+            if (byteCodeIndex - stopCheck > 1) {
+                String err = "bad finish for method " + m.getName() +
+                             "End + "  + (byteCodeIndex - stopCheck);
+                throw new IllegalArgumentException(err);
+            }
+        }
+    }
+
+    private MethodInfo[] decodeMethods(ConstantPoolEntry[] constantPool) {
+        MethodInfo[] methods = new MethodInfo[cursor.readUnsignedShort()];
+
+        for (int i = 0; i < methods.length; i++) {
+            cursor.readUnsignedShort(); // access flags
+
+            String name = constantPool[cursor.readUnsignedShort()].getValue();
+            String descriptor = constantPool[cursor.readUnsignedShort()].getValue();
+
+            int codeLength = 0;
+            int codeStart = 0;
+
+            int numAttributes = cursor.readUnsignedShort(); // attributes count
+            for (int j = 0; j < numAttributes; j++) {
+                int type = cursor.readUnsignedShort(); // attrib nameIndex
+                int aLen = cursor.readInt(); // attrib length
+
+                if (constantPool[type].getValue().equals("Code")) {
+                    cursor.readUnsignedShort(); // Max stack
+                    cursor.readUnsignedShort(); // Max locals
+
+                    codeLength = cursor.readInt();
+                    codeStart = cursor.getOffset();
+
+                    cursor.skipBytes(codeLength); // Need to skip the code bytes
+                    cursor.skipBytes(cursor.readUnsignedShort() * 8); // Skip exception table
+
+                    int numSubAttributes = cursor.readUnsignedShort();
+                    for (int k = 0; k < numSubAttributes; k++) {
+                        cursor.readUnsignedShort(); // sub name
+                        cursor.skipBytes(cursor.readInt()); // sub attrib data
+                    }
+                } else {
+                    cursor.skipBytes(aLen); // unknown attrib data
+                }
+            }
+
+            methods[i] = new MethodInfo(name, descriptor, codeLength, codeStart);
+        }
+
+        return methods;
+    }
+
+    private void decodeFields() {
+        // Looks like we dont need any field info, throw it away!
+        int numFields = cursor.readUnsignedShort();
+
+        for (int i = 0; i < numFields; i++) {
+            cursor.readUnsignedShort(); // access flags
+            cursor.readUnsignedShort(); // nameIndex
+            cursor.readUnsignedShort(); // descriptorIndex
+
+            int numAttributes = cursor.readUnsignedShort();
+            for (int j = 0; j < numAttributes; j++) {
+                cursor.readUnsignedShort(); // nameIndex
+                int length = cursor.readInt();
+                cursor.skipBytes(length); // data
+            }
+        }
+    }
+
+    private ConstantPoolEntry[] decodeConstantPool() {
+        final int CONSTANT_Utf8 = 1;
+        final int CONSTANT_Unicode = 2;
+        final int CONSTANT_Integer = 3;
+        final int CONSTANT_Float = 4;
+        final int CONSTANT_Long = 5;
+        final int CONSTANT_Double = 6;
+        final int CONSTANT_Class = 7;
+        final int CONSTANT_String = 8;
+        final int CONSTANT_Fieldref = 9;
+        final int CONSTANT_Methodref = 10;
+        final int CONSTANT_InterfaceMethodref = 11;
+        final int CONSTANT_NameAndType = 12;
+        final int CONSTANT_MethodHandle = 15;
+        final int CONSTANT_MethodType = 16;
+        final int CONSTANT_InvokeDynamic = 18;
+
+        ConstantPoolEntry[] constantPool = new ConstantPoolEntry[cursor.readUnsignedShort()];
+
+        // The constant pool starts at index 1
+        for (int i = 1; i < constantPool.length; i++) {
+            int type = cursor.readUnsignedByte();
+
+            switch (type) {
+                case CONSTANT_Class:
+                    constantPool[i] = new ConstantPoolEntry(cursor.readUnsignedShort()); // name_index
+                    break;
+
+                case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref:
+                    constantPool[i] = new ConstantPoolEntry(cursor.readUnsignedShort()); // class_index
+                    cursor.readUnsignedShort(); // name_and_type_index
+                    break;
+
+                case CONSTANT_String:
+                    cursor.readUnsignedShort(); // string_index
+                    break;
+
+                case CONSTANT_Integer:
+                    cursor.readInt(); // bytes
+                    break;
+
+                case CONSTANT_Float:
+                    cursor.readInt(); // bytes
+                    break;
+
+                case CONSTANT_Long:
+                    cursor.readInt(); // high_bytes
+                    cursor.readInt(); // low_bytes
+                    i++; // 8 byte constants use 2 constant pool slots.
+                    break;
+
+                case CONSTANT_Double:
+                    cursor.readInt(); // high_bytes
+                    cursor.readInt(); // low_bytes
+                    i++; // 8 byte constants use 2 constant pool slots.
+                    break;
+
+                case CONSTANT_NameAndType:
+                    constantPool[i] = new ConstantPoolEntry(cursor.readUnsignedShort()); // name_index
+                    cursor.readUnsignedShort(); // descriptor_index
+                    break;
+
+                case CONSTANT_Utf8:
+                    int length = cursor.readUnsignedShort(); // length
+                    constantPool[i] = new ConstantPoolEntry(cursor.readUtf8(length)); // bytes[length]
+                    break;
+
+                case CONSTANT_MethodHandle:
+                    cursor.readUnsignedByte(); // reference_kind
+                    cursor.readUnsignedShort(); // reference_index
+                    break;
+
+                case CONSTANT_MethodType:
+                    cursor.readUnsignedShort(); // descriptor_index
+                    break;
+
+                case CONSTANT_InvokeDynamic:
+                    cursor.readUnsignedShort(); // bootstrap_method_attr_index
+                    cursor.readUnsignedShort(); // name_and_type_index
+                    break;
+
+                default:
+                    String err = "Unknown constant pool type " + String.valueOf(type) + "\n" +
+                                 "CPE " + i + " of " + constantPool.length + "\n" +
+                                 "Byte offset " + Integer.toHexString(cursor.getOffset());
+                    throw new IllegalArgumentException(err);
+            }
+        }
+        return constantPool;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/Dependency.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+class Dependency {
+    private String methodName;
+    private String methodDescriptor;
+    private String target;
+
+    public Dependency(String methodName, String methodDescriptor, String target) {
+        this.methodName = methodName;
+        this.methodDescriptor = methodDescriptor;
+        this.target = target;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof Dependency)) {
+            return false;
+        }
+
+        Dependency other = (Dependency)o;
+        return target.equals(other.target) &&
+               methodName.equals(other.methodName) &&
+               methodDescriptor.equals(other.methodDescriptor);
+    }
+
+    @Override
+    public int hashCode() {
+        return methodName.hashCode() ^ methodDescriptor.hashCode() ^ target.hashCode();
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/MethodInfo.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+class MethodInfo {
+    private String name;
+    private String descriptor;
+    private int codeLength;
+    private int codeStart;
+
+    public MethodInfo(String name, String descriptor, int codeLength, int codeStart) {
+        this.name = name;
+        this.descriptor = descriptor;
+        this.codeLength = codeLength;
+        this.codeStart = codeStart;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getDescriptor() {
+        return descriptor;
+    }
+
+    public int getCodeLength() {
+        return codeLength;
+    }
+
+    public int getCodeStart() {
+        return codeStart;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/TestGCBasher.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystems;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.stream.Stream;
+
+public class TestGCBasher {
+    private static void parseClassFiles() throws IOException {
+        HashMap<String, ClassInfo> deps = new HashMap<>();
+
+        FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+        Stream<Path> s = Files.walk(fs.getPath("/"));
+        for (Path p : (Iterable<Path>)s::iterator) {
+            if (p.toString().endsWith(".class")) {
+                byte[] data = Files.readAllBytes(p);
+                Decompiler d = new Decompiler(data);
+                ClassInfo ci = d.getClassInfo();
+                deps.put(ci.getName(), ci);
+            }
+        }
+    }
+
+    public static void run(String[] args) throws IOException {
+        if (args.length != 1) {
+            System.err.println("Usage: TestGCBasher <duration-ms>");
+            return;
+        }
+
+        long durationMillis = Long.valueOf(args[0]);
+        long start = System.currentTimeMillis();
+        while (System.currentTimeMillis() - start < durationMillis) {
+            parseClassFiles();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.IOException;
+
+/*
+ * @test TestGCBasherWithCMS
+ * @key gc
+ * @key stress
+ * @requires vm.gc.ConcMarkSweep
+ * @requires vm.flavor == "server"
+ * @summary Stress the CMS GC by trying to make old objects more likely to be garbage than young objects.
+ * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx128m -server -XX:+UseConcMarkSweepGC TestGCBasherWithCMS 120000
+ */
+public class TestGCBasherWithCMS {
+    public static void main(String[] args) throws IOException {
+        TestGCBasher.run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.IOException;
+
+/*
+ * @test TestGCBasherWithG1
+ * @key gc
+ * @key stress
+ * @requires vm.gc.G1
+ * @requires vm.flavor == "server"
+ * @summary Stress the G1 GC by trying to make old objects more likely to be garbage than young objects.
+ * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx128m -server -XX:+UseG1GC TestGCBasherWithG1 120000
+ */
+public class TestGCBasherWithG1 {
+    public static void main(String[] args) throws IOException {
+        TestGCBasher.run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithParallel.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.IOException;
+
+/*
+ * @test TestGCBasherWithParallel
+ * @key gc
+ * @key stress
+ * @requires vm.gc.Parallel
+ * @requires vm.flavor == "server"
+ * @summary Stress the Parallel GC by trying to make old objects more likely to be garbage than young objects.
+ * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx256m -server -XX:+UseParallelGC -XX:-UseGCOverheadLimit TestGCBasherWithParallel 120000
+ */
+public class TestGCBasherWithParallel {
+    public static void main(String[] args) throws IOException {
+        TestGCBasher.run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java	Thu Oct 06 16:32:46 2016 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.IOException;
+
+/*
+ * @test TestGCBasherWithSerial
+ * @key gc
+ * @key stress
+ * @requires vm.gc.Serial
+ * @requires vm.flavor == "server"
+ * @summary Stress the Serial GC by trying to make old objects more likely to be garbage than young objects.
+ * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx128m -server -XX:+UseSerialGC TestGCBasherWithSerial 120000
+ */
+public class TestGCBasherWithSerial {
+    public static void main(String[] args) throws IOException {
+        TestGCBasher.run(args);
+    }
+}