8129962: Investigate performance improvements in langtools combo tests
authormcimadamore
Mon, 31 Aug 2015 17:33:34 +0100
changeset 32454 b0ac04e0fefe
parent 32453 8eebd1f0b8ea
child 32455 98687c25039e
8129962: Investigate performance improvements in langtools combo tests Summary: New combo API that runs all combo instances in a shared javac context (whenever possible). Reviewed-by: jjg, jlahoda, vromero
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Context.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java
langtools/test/tools/javac/Diagnostics/6769027/T6769027.java
langtools/test/tools/javac/T7093325.java
langtools/test/tools/javac/TestBootstrapMethodsCount.java
langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java
langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java
langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java
langtools/test/tools/javac/failover/CheckAttributedTree.java
langtools/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java
langtools/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java
langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java
langtools/test/tools/javac/lambda/LambdaParserTest.java
langtools/test/tools/javac/lambda/MethodReferenceParserTest.java
langtools/test/tools/javac/lambda/TestBootstrapMethodsCount.java
langtools/test/tools/javac/lambda/TestInvokeDynamic.java
langtools/test/tools/javac/lambda/TestLambdaToMethodStats.java
langtools/test/tools/javac/lambda/bytecode/TestLambdaBytecode.java
langtools/test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.java
langtools/test/tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java
langtools/test/tools/javac/lib/JavacTestingAbstractThreadedTest.java
langtools/test/tools/javac/lib/combo/ComboInstance.java
langtools/test/tools/javac/lib/combo/ComboParameter.java
langtools/test/tools/javac/lib/combo/ComboTask.java
langtools/test/tools/javac/lib/combo/ComboTestHelper.java
langtools/test/tools/javac/lib/combo/ReusableContext.java
langtools/test/tools/javac/multicatch/7030606/DisjunctiveTypeWellFormednessTest.java
langtools/test/tools/javac/resolve/BitWiseOperators.java
langtools/test/tools/javac/types/ScopeListenerTest.java
langtools/test/tools/javac/varargs/7042566/T7042566.java
langtools/test/tools/javac/varargs/warning/Warn4.java
langtools/test/tools/javac/varargs/warning/Warn5.java
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Mon Aug 31 17:33:34 2015 +0100
@@ -76,7 +76,7 @@
     private final AtomicBoolean used = new AtomicBoolean();
     private Iterable<? extends Processor> processors;
 
-    JavacTaskImpl(Context context) {
+    protected JavacTaskImpl(Context context) {
         super(context, true);
         args = Arguments.instance(context);
         fileManager = context.get(JavaFileManager.class);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java	Mon Aug 31 17:33:34 2015 +0100
@@ -47,6 +47,9 @@
     /** The context key for the MultiTaskListener. */
     public static final Context.Key<MultiTaskListener> taskListenerKey = new Context.Key<>();
 
+    /** Empty array of task listeners */
+    private static final TaskListener[] EMPTY_LISTENERS = new TaskListener[0];
+
     /** Get the MultiTaskListener instance for this context. */
     public static MultiTaskListener instance(Context context) {
         MultiTaskListener instance = context.get(taskListenerKey);
@@ -64,7 +67,7 @@
      * The current set of registered listeners.
      * This is a mutable reference to an immutable array.
      */
-    TaskListener[] listeners = { };
+    TaskListener[] listeners = EMPTY_LISTENERS;
 
     ClientCodeWrapper ccw;
 
@@ -73,7 +76,7 @@
     }
 
     public boolean isEmpty() {
-        return (listeners.length == 0);
+        return listeners == EMPTY_LISTENERS;
     }
 
     public void add(TaskListener listener) {
@@ -88,10 +91,14 @@
     public void remove(TaskListener listener) {
         for (int i = 0; i < listeners.length; i++) {
             if (ccw.unwrap(listeners[i]) == listener) {
-                TaskListener[] newListeners = new TaskListener[listeners.length - 1];
-                System.arraycopy(listeners, 0, newListeners, 0, i);
-                System.arraycopy(listeners, i + 1, newListeners, i, newListeners.length - i);
-                listeners = newListeners;
+                if (listeners.length == 1) {
+                    listeners = EMPTY_LISTENERS;
+                } else {
+                    TaskListener[] newListeners = new TaskListener[listeners.length - 1];
+                    System.arraycopy(listeners, 0, newListeners, 0, i);
+                    System.arraycopy(listeners, i + 1, newListeners, i, newListeners.length - i);
+                    listeners = newListeners;
+                }
                 break;
             }
         }
@@ -117,4 +124,8 @@
     public String toString() {
         return Arrays.toString(listeners);
     }
+
+    public void clear() {
+        listeners = EMPTY_LISTENERS;
+    }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java	Mon Aug 31 17:33:34 2015 +0100
@@ -26,6 +26,7 @@
 package com.sun.tools.javac.code;
 
 import com.sun.tools.javac.code.Kinds.Kind;
+import java.lang.ref.WeakReference;
 import java.util.*;
 import java.util.function.BiConsumer;
 import java.util.stream.Stream;
@@ -162,15 +163,49 @@
 
     /** A list of scopes to be notified if items are to be removed from this scope.
      */
-    List<ScopeListener> listeners = List.nil();
+    ScopeListenerList listeners = new ScopeListenerList();
 
-    public void addScopeListener(ScopeListener sl) {
-        listeners = listeners.prepend(sl);
+    public interface ScopeListener {
+        void symbolAdded(Symbol sym, Scope s);
+        void symbolRemoved(Symbol sym, Scope s);
     }
 
-    public interface ScopeListener {
-        public void symbolAdded(Symbol sym, Scope s);
-        public void symbolRemoved(Symbol sym, Scope s);
+    /**
+     * A list of scope listeners; listeners are stored in weak references, to avoid memory leaks.
+     * When the listener list is scanned (upon notification), elements corresponding to GC-ed
+     * listeners are removed so that the listener list size is kept in check.
+     */
+    public static class ScopeListenerList {
+
+        List<WeakReference<ScopeListener>> listeners = List.nil();
+
+        void add(ScopeListener sl) {
+            listeners = listeners.prepend(new WeakReference<>(sl));
+        }
+
+        void symbolAdded(Symbol sym, Scope scope) {
+            walkReferences(sym, scope, false);
+        }
+
+        void symbolRemoved(Symbol sym, Scope scope) {
+            walkReferences(sym, scope, true);
+        }
+
+        private void walkReferences(Symbol sym, Scope scope, boolean isRemove) {
+            ListBuffer<WeakReference<ScopeListener>> newListeners = new ListBuffer<>();
+            for (WeakReference<ScopeListener> wsl : listeners) {
+                ScopeListener sl = wsl.get();
+                if (sl != null) {
+                    if (isRemove) {
+                        sl.symbolRemoved(sym, scope);
+                    } else {
+                        sl.symbolAdded(sym, scope);
+                    }
+                    newListeners.add(wsl);
+                }
+            }
+            listeners = newListeners.toList();
+        }
     }
 
     public enum LookupKind {
@@ -404,9 +439,7 @@
             elems = e;
 
             //notify listeners
-            for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) {
-                l.head.symbolAdded(sym, this);
-            }
+            listeners.symbolAdded(sym, this);
         }
 
         /** Remove symbol from this scope.
@@ -442,9 +475,7 @@
             }
 
             //notify listeners
-            for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) {
-                l.head.symbolRemoved(sym, this);
-            }
+            listeners.symbolRemoved(sym, this);
         }
 
         /** Enter symbol sym in this scope if not already there.
@@ -698,11 +729,12 @@
                         finalized.enter(sym);
                     }
 
-                    finalized.addScopeListener(new ScopeListener() {
+                    finalized.listeners.add(new ScopeListener() {
                         @Override
                         public void symbolAdded(Symbol sym, Scope s) {
                             Assert.error("The scope is sealed.");
                         }
+
                         @Override
                         public void symbolRemoved(Symbol sym, Scope s) {
                             Assert.error("The scope is sealed.");
@@ -929,26 +961,20 @@
         public void prependSubScope(Scope that) {
            if (that != null) {
                 subScopes = subScopes.prepend(that);
-                that.addScopeListener(this);
+                that.listeners.add(this);
                 mark++;
-                for (ScopeListener sl : listeners) {
-                    sl.symbolAdded(null, this); //propagate upwards in case of nested CompoundScopes
-                }
+                listeners.symbolAdded(null, this);
            }
         }
 
         public void symbolAdded(Symbol sym, Scope s) {
             mark++;
-            for (ScopeListener sl : listeners) {
-                sl.symbolAdded(sym, s);
-            }
+            listeners.symbolAdded(sym, s);
         }
 
         public void symbolRemoved(Symbol sym, Scope s) {
             mark++;
-            for (ScopeListener sl : listeners) {
-                sl.symbolRemoved(sym, s);
-            }
+            listeners.symbolRemoved(sym, s);
         }
 
         public int getMark() {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java	Mon Aug 31 17:33:34 2015 +0100
@@ -68,7 +68,7 @@
     /**
      * The context key for the arguments.
      */
-    protected static final Context.Key<Arguments> argsKey = new Context.Key<>();
+    public static final Context.Key<Arguments> argsKey = new Context.Key<>();
 
     private String ownName;
     private Set<String> classNames;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Mon Aug 31 17:33:34 2015 +0100
@@ -87,7 +87,7 @@
  */
 public class JavaCompiler {
     /** The context key for the compiler. */
-    protected static final Context.Key<JavaCompiler> compilerKey = new Context.Key<>();
+    public static final Context.Key<JavaCompiler> compilerKey = new Context.Key<>();
 
     /** Get the JavaCompiler instance for this context. */
     public static JavaCompiler instance(Context context) {
@@ -821,7 +821,7 @@
         // as a JavaCompiler can only be used once, throw an exception if
         // it has been used before.
         if (hasBeenUsed)
-            throw new AssertionError("attempt to reuse JavaCompiler");
+            checkReusable();
         hasBeenUsed = true;
 
         // forcibly set the equivalent of -Xlint:-options, so that no further
@@ -898,6 +898,10 @@
         }
     }
 
+    protected void checkReusable() {
+        throw new AssertionError("attempt to reuse JavaCompiler");
+    }
+
     /**
      * Set needRootClasses to true, in JavaCompiler subclass constructor
      * that want to collect public apis of classes supplied on the command line.
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Context.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Context.java	Mon Aug 31 17:33:34 2015 +0100
@@ -119,7 +119,7 @@
      * or
      * {@literal Key<T> -> Factory<T> }
      */
-    private final Map<Key<?>,Object> ht = new HashMap<>();
+    protected final Map<Key<?>,Object> ht = new HashMap<>();
 
     /** Set the factory for the key in this context. */
     public <T> void put(Key<T> key, Factory<T> fac) {
@@ -173,7 +173,7 @@
      */
     private final Map<Class<?>, Key<?>> kt = new HashMap<>();
 
-    private <T> Key<T> key(Class<T> clss) {
+    protected <T> Key<T> key(Class<T> clss) {
         checkState(kt);
         Key<T> k = uncheckedCast(kt.get(clss));
         if (k == null) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java	Mon Aug 31 17:33:34 2015 +0100
@@ -334,7 +334,7 @@
      *  error message more than once. For each error, a pair consisting of the
      *  source file name and source code position of the error is added to the set.
      */
-    private Set<Pair<JavaFileObject, Integer>> recorded = new HashSet<>();
+    protected Set<Pair<JavaFileObject, Integer>> recorded = new HashSet<>();
 
     public boolean hasDiagnosticListener() {
         return diagListener != null;
--- a/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java	Mon Aug 31 17:33:34 2015 +0100
@@ -25,26 +25,19 @@
  * @test
  * @bug     6769027 8006694
  * @summary Source line should be displayed immediately after the first diagnostic line
- *  temporarily workaround combo tests are causing time out in several platforms
- * @author  Maurizio Cimadamore
- * @library ../../lib
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
  * @run main/othervm T6769027
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+// use /othervm to avoid locale issues
 
 import java.net.URI;
 import java.util.regex.Matcher;
 import javax.tools.*;
 import com.sun.tools.javac.util.*;
 
-public class T6769027
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+public class T6769027 {
 
     enum OutputKind {
         RAW("rawDiagnostics","rawDiagnostics"),
@@ -324,11 +317,6 @@
         }
 
         @Override
-        protected java.io.PrintWriter getWriterForDiagnosticType(JCDiagnostic.DiagnosticType dt) {
-            return outWriter;
-        }
-
-        @Override
         protected boolean shouldReport(JavaFileObject jfo, int pos) {
             return true;
         }
@@ -368,7 +356,6 @@
         this.subdiagsIndent = subdiagsIndent;
     }
 
-    @Override
     public void run() {
         Context ctx = new Context();
         Options options = Options.instance(ctx);
@@ -419,7 +406,7 @@
                                                 for (IndentKind detailsIndent : IndentKind.values()) {
                                                     for (IndentKind sourceIndent : IndentKind.values()) {
                                                         for (IndentKind subdiagsIndent : IndentKind.values()) {
-                                                            pool.execute(new T6769027(outputKind,
+                                                            new T6769027(outputKind,
                                                                 errKind,
                                                                 multiKind,
                                                                 multiPolicy,
@@ -431,7 +418,7 @@
                                                                 summaryIndent,
                                                                 detailsIndent,
                                                                 sourceIndent,
-                                                                subdiagsIndent));
+                                                                subdiagsIndent).run();
                                                         }
                                                     }
                                                 }
@@ -445,8 +432,6 @@
                 }
             }
         }
-
-        checkAfterExec(false);
     }
 
     void printInfo(String msg, String errorLine) {
@@ -457,11 +442,11 @@
                 " caret=" + caretKind + " sourcePosition=" + sourceLineKind +
                 " summaryIndent=" + summaryIndent + " detailsIndent=" + detailsIndent +
                 " sourceIndent=" + sourceIndent + " subdiagsIndent=" + subdiagsIndent;
-        errWriter.println(sep);
-        errWriter.println(desc);
-        errWriter.println(sep);
-        errWriter.println(msg);
-        errWriter.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine);
+        System.err.println(sep);
+        System.err.println(desc);
+        System.err.println(sep);
+        System.err.println(msg);
+        System.err.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine);
     }
 
     void checkOutput(String msg) {
@@ -494,8 +479,8 @@
         }
 
         if (!msg.equals(errorLine)) {
-//            printInfo(msg, errorLine);
-            errCount.incrementAndGet();
+            printInfo(msg, errorLine);
+            throw new AssertionError("errors were found");
         }
     }
 
--- a/langtools/test/tools/javac/T7093325.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/T7093325.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,38 +23,41 @@
 
 /*
  * @test
- * @bug 7093325 8006694
+ * @bug 7093325 8006694 8129962
  * @summary Redundant entry in bytecode exception table
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library lib
+ * @library /tools/javac/lib
  * @modules jdk.jdeps/com.sun.tools.classfile
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm T7093325
+ *          jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main T7093325
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
+import java.io.InputStream;
 
-import java.io.File;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-
-import com.sun.source.util.JavacTask;
 import com.sun.tools.classfile.Attribute;
 import com.sun.tools.classfile.ClassFile;
 import com.sun.tools.classfile.Code_attribute;
-import com.sun.tools.classfile.ConstantPool.*;
+import com.sun.tools.classfile.ConstantPoolException;
 import com.sun.tools.classfile.Method;
 
-public class T7093325
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+import javax.tools.JavaFileObject;
 
-    enum StatementKind {
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
+
+public class T7093325 extends ComboInstance<T7093325> {
+
+    enum StatementKind implements ComboParameter {
+        NONE(null, false, false),
         THROW("throw new RuntimeException();", false, false),
         RETURN_NONEMPTY("System.out.println(); return;", true, false),
         RETURN_EMPTY("return;", true, true),
@@ -64,107 +67,79 @@
         boolean canInline;
         boolean empty;
 
-        private StatementKind(String stmt, boolean canInline, boolean empty) {
+        StatementKind(String stmt, boolean canInline, boolean empty) {
             this.stmt = stmt;
             this.canInline = canInline;
             this.empty = empty;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return stmt;
+        }
     }
 
-    enum CatchArity {
+    enum CatchArity implements ComboParameter {
         NONE(""),
-        ONE("catch (A a) { #S1 }"),
-        TWO("catch (B b) { #S2 }"),
-        THREE("catch (C c) { #S3 }"),
-        FOUR("catch (D d) { #S4 }");
+        ONE("catch (A a) { #{STMT[1]} }"),
+        TWO("catch (B b) { #{STMT[2]} }"),
+        THREE("catch (C c) { #{STMT[3]} }"),
+        FOUR("catch (D d) { #{STMT[4]} }");
 
         String catchStr;
 
-        private CatchArity(String catchStr) {
+        CatchArity(String catchStr) {
             this.catchStr = catchStr;
         }
 
-        String catchers() {
+        @Override
+        public String expand(String optParameter) {
             if (this.ordinal() == 0) {
                 return catchStr;
             } else {
-                return CatchArity.values()[this.ordinal() - 1].catchers() +
+                return CatchArity.values()[this.ordinal() - 1].expand(optParameter) +
                         catchStr;
             }
         }
     }
 
     public static void main(String... args) throws Exception {
-        for (CatchArity ca : CatchArity.values()) {
-            for (StatementKind stmt0 : StatementKind.values()) {
-                if (ca.ordinal() == 0) {
-                    pool.execute(new T7093325(ca, stmt0));
-                    continue;
-                }
-                for (StatementKind stmt1 : StatementKind.values()) {
-                    if (ca.ordinal() == 1) {
-                        pool.execute(new T7093325(ca, stmt0, stmt1));
-                        continue;
-                    }
-                    for (StatementKind stmt2 : StatementKind.values()) {
-                        if (ca.ordinal() == 2) {
-                            pool.execute(new T7093325(ca, stmt0, stmt1, stmt2));
-                            continue;
-                        }
-                        for (StatementKind stmt3 : StatementKind.values()) {
-                            if (ca.ordinal() == 3) {
-                                pool.execute(
-                                    new T7093325(ca, stmt0, stmt1, stmt2, stmt3));
-                                continue;
-                            }
-                            for (StatementKind stmt4 : StatementKind.values()) {
-                                if (ca.ordinal() == 4) {
-                                    pool.execute(
-                                        new T7093325(ca, stmt0, stmt1,
-                                                     stmt2, stmt3, stmt4));
-                                    continue;
-                                }
-                                for (StatementKind stmt5 : StatementKind.values()) {
-                                    pool.execute(
-                                        new T7093325(ca, stmt0, stmt1, stmt2,
-                                                     stmt3, stmt4, stmt5));
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec();
+        new ComboTestHelper<T7093325>()
+                .withFilter(T7093325::testFilter)
+                .withDimension("CATCH", (x, ca) -> x.ca = ca, CatchArity.values())
+                .withArrayDimension("STMT", (x, stmt, idx) -> x.stmts[idx] = stmt, 5, StatementKind.values())
+                .run(T7093325::new);
     }
 
     /** instance decls **/
 
     CatchArity ca;
-    StatementKind[] stmts;
+    StatementKind[] stmts = new StatementKind[5];
 
-    public T7093325(CatchArity ca, StatementKind... stmts) {
-        this.ca = ca;
-        this.stmts = stmts;
+    boolean testFilter() {
+        int lastPos = ca.ordinal() + 1;
+        for (int i = 0; i < stmts.length ; i++) {
+            boolean shouldBeSet = i < lastPos;
+            boolean isSet = stmts[i] != StatementKind.NONE;
+            if (shouldBeSet != isSet) {
+                return false;
+            }
+        }
+        return true;
     }
 
     @Override
-    public void run() {
-        int id = checkCount.incrementAndGet();
-        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
-        JavaSource source = new JavaSource(id);
-        JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), null,
-                null, null, Arrays.asList(source));
-        ct.call();
-        verifyBytecode(source, id);
+    public void doWork() throws IOException {
+        verifyBytecode(newCompilationTask()
+                .withSourceFromTemplate(source_template)
+                .generate());
     }
 
-    void verifyBytecode(JavaSource source, int id) {
+    void verifyBytecode(Result<Iterable<? extends JavaFileObject>> result) {
         boolean lastInlined = false;
         boolean hasCode = false;
         int gapsCount = 0;
-        for (int i = 0; i < stmts.length ; i++) {
+        for (int i = 0; i < ca.ordinal() + 1 ; i++) {
             lastInlined = stmts[i].canInline;
             hasCode = hasCode || !stmts[i].empty;
             if (lastInlined && hasCode) {
@@ -176,12 +151,11 @@
             gapsCount++;
         }
 
-        File compiledTest = new File(String.format("Test%s.class", id));
-        try {
-            ClassFile cf = ClassFile.read(compiledTest);
+        try (InputStream is = result.get().iterator().next().openInputStream()) {
+            ClassFile cf = ClassFile.read(is);
             if (cf == null) {
-                throw new Error("Classfile not found: " +
-                                compiledTest.getName());
+                fail("Classfile not found: " + result.compilationInfo());
+                return;
             }
 
             Method test_method = null;
@@ -193,7 +167,8 @@
             }
 
             if (test_method == null) {
-                throw new Error("Method test() not found in class Test");
+                fail("Method test() not found in class Test" + result.compilationInfo());
+                return;
             }
 
             Code_attribute code = null;
@@ -205,7 +180,8 @@
             }
 
             if (code == null) {
-                throw new Error("Code attribute not found in method test()");
+                fail("Code attribute not found in method test()");
+                return;
             }
 
             int actualGapsCount = 0;
@@ -217,54 +193,28 @@
             }
 
             if (actualGapsCount != gapsCount) {
-                throw new Error("Bad exception table for test()\n" +
+                fail("Bad exception table for test()\n" +
                             "expected gaps: " + gapsCount + "\n" +
                             "found gaps: " + actualGapsCount + "\n" +
-                            source);
+                        result.compilationInfo());
+                return;
             }
-        } catch (Exception e) {
+        } catch (IOException | ConstantPoolException e) {
             e.printStackTrace();
-            throw new Error("error reading " + compiledTest +": " + e);
+            fail("error reading classfile: " + e);
         }
 
     }
 
-    class JavaSource extends SimpleJavaFileObject {
-
-        static final String source_template =
+    static final String source_template =
+                "class Test {\n" +
+                "   void test() {\n" +
+                "   try { #{STMT[0]} } #{CATCH} finally { System.out.println(); }\n" +
+                "   }\n" +
+                "}\n" +
                 "class A extends RuntimeException {} \n" +
                 "class B extends RuntimeException {} \n" +
                 "class C extends RuntimeException {} \n" +
                 "class D extends RuntimeException {} \n" +
-                "class E extends RuntimeException {} \n" +
-                "class Test#ID {\n" +
-                "   void test() {\n" +
-                "   try { #S0 } #C finally { System.out.println(); }\n" +
-                "   }\n" +
-                "}";
-
-        String source;
-
-        public JavaSource(int id) {
-            super(URI.create(String.format("myfo:/Test%s.java", id)),
-                  JavaFileObject.Kind.SOURCE);
-            source = source_template.replace("#C", ca.catchers());
-            source = source.replace("#S0", stmts[0].stmt);
-            source = source.replace("#ID", String.valueOf(id));
-            for (int i = 1; i < ca.ordinal() + 1; i++) {
-                source = source.replace("#S" + i, stmts[i].stmt);
-            }
-        }
-
-        @Override
-        public String toString() {
-            return source;
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
-    }
-
+                "class E extends RuntimeException {}";
 }
--- a/langtools/test/tools/javac/TestBootstrapMethodsCount.java	Mon Aug 31 15:50:20 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,236 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, 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.
- */
-
-/*
- * @test
- * @bug 8129547
- * @summary Excess entries in BootstrapMethods with the same (bsm, bsmKind, bsmStaticArgs), but different dynamicArgs
- * @library lib
- * @modules jdk.jdeps/com.sun.tools.classfile
- *          jdk.compiler/com.sun.tools.javac.api
- *          jdk.compiler/com.sun.tools.javac.code
- *          jdk.compiler/com.sun.tools.javac.jvm
- *          jdk.compiler/com.sun.tools.javac.tree
- *          jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm TestBootstrapMethodsCount
- */
-
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Locale;
-
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-
-import com.sun.source.tree.MethodInvocationTree;
-import com.sun.source.tree.MethodTree;
-import com.sun.source.util.TaskEvent;
-import com.sun.source.util.TaskListener;
-import com.sun.source.util.TreeScanner;
-
-import com.sun.tools.classfile.Attribute;
-import com.sun.tools.classfile.BootstrapMethods_attribute;
-import com.sun.tools.classfile.ClassFile;
-
-import com.sun.tools.javac.api.JavacTaskImpl;
-import com.sun.tools.javac.code.Symbol;
-import com.sun.tools.javac.code.Symbol.MethodSymbol;
-import com.sun.tools.javac.code.Symtab;
-import com.sun.tools.javac.code.Types;
-import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
-import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
-import com.sun.tools.javac.tree.JCTree.JCIdent;
-import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.Names;
-
-import static com.sun.tools.javac.jvm.ClassFile.*;
-
-public class TestBootstrapMethodsCount
-        extends JavacTestingAbstractThreadedTest
-        implements Runnable {
-
-
-    public static void main(String... args) throws Exception {
-        pool.execute(new TestBootstrapMethodsCount());
-        checkAfterExec();
-    }
-
-    DiagChecker dc;
-
-    TestBootstrapMethodsCount() {
-        dc = new DiagChecker();
-    }
-
-    public void run() {
-        int id = checkCount.incrementAndGet();
-        JavaSource source = new JavaSource(id);
-        JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc,
-                Arrays.asList("-g"), null, Arrays.asList(source));
-        Context context = ct.getContext();
-        Symtab syms = Symtab.instance(context);
-        Names names = Names.instance(context);
-        Types types = Types.instance(context);
-        ct.addTaskListener(new Indifier(syms, names, types));
-        try {
-            ct.generate();
-        } catch (Throwable t) {
-            t.printStackTrace();
-            throw new AssertionError(
-                    String.format("Error thrown when compiling following code\n%s",
-                            source.source));
-        }
-        if (dc.diagFound) {
-            throw new AssertionError(
-                    String.format("Diags found when compiling following code\n%s\n\n%s",
-                            source.source, dc.printDiags()));
-        }
-        verifyBytecode(id);
-    }
-
-    void verifyBytecode(int id) {
-        File compiledTest = new File(String.format("Test%d.class", id));
-        try {
-            ClassFile cf = ClassFile.read(compiledTest);
-            BootstrapMethods_attribute bsm_attr =
-                    (BootstrapMethods_attribute)cf
-                            .getAttribute(Attribute.BootstrapMethods);
-            int length = bsm_attr.bootstrap_method_specifiers.length;
-            if (length != 1) {
-                throw new Error("Bad number of method specifiers " +
-                        "in BootstrapMethods attribute: " + length);
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-            throw new Error("error reading " + compiledTest +": " + e);
-        }
-    }
-
-    class JavaSource extends SimpleJavaFileObject {
-
-        static final String source_template = "import java.lang.invoke.*;\n" +
-                "class Bootstrap {\n" +
-                "   public static CallSite bsm(MethodHandles.Lookup lookup, " +
-                "String name, MethodType methodType) {\n" +
-                "       return null;\n" +
-                "   }\n" +
-                "}\n" +
-                "class Test#ID {\n" +
-                "   void m1() { }\n" +
-                "   void m2(Object arg1) { }\n" +
-                "   void test1() {\n" +
-                "      Object o = this; // marker statement \n" +
-                "      m1();\n" +
-                "   }\n" +
-                "   void test2(Object arg1) {\n" +
-                "      Object o = this; // marker statement \n" +
-                "      m2(arg1);\n" +
-                "   }\n" +
-                "}";
-
-        String source;
-
-        JavaSource(int id) {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = source_template.replace("#ID", String.valueOf(id));
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
-    }
-
-    class Indifier extends TreeScanner<Void, Void> implements TaskListener {
-
-        MethodSymbol bsm;
-        Symtab syms;
-        Names names;
-        Types types;
-
-        Indifier(Symtab syms, Names names, Types types) {
-            this.syms = syms;
-            this.names = names;
-            this.types = types;
-        }
-
-        @Override
-        public void started(TaskEvent e) {
-            //do nothing
-        }
-
-        @Override
-        public void finished(TaskEvent e) {
-            if (e.getKind() == TaskEvent.Kind.ANALYZE) {
-                scan(e.getCompilationUnit(), null);
-            }
-        }
-
-        @Override
-        public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
-            super.visitMethodInvocation(node, p);
-            JCMethodInvocation apply = (JCMethodInvocation)node;
-            JCIdent ident = (JCIdent)apply.meth;
-            Symbol oldSym = ident.sym;
-            if (!oldSym.isConstructor()) {
-                ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name,
-                        oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]);
-            }
-            return null;
-        }
-
-        @Override
-        public Void visitMethod(MethodTree node, Void p) {
-            super.visitMethod(node, p);
-            if (node.getName().toString().equals("bsm")) {
-                bsm = ((JCMethodDecl)node).sym;
-            }
-            return null;
-        }
-    }
-
-    static class DiagChecker
-            implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean diagFound;
-        ArrayList<String> diags = new ArrayList<>();
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            diags.add(diagnostic.getMessage(Locale.getDefault()));
-            diagFound = true;
-        }
-
-        String printDiags() {
-            StringBuilder buf = new StringBuilder();
-            for (String s : diags) {
-                buf.append(s);
-                buf.append("\n");
-            }
-            return buf.toString();
-        }
-    }
-
-}
--- a/langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,53 +23,47 @@
 
 /*
  * @test
- * @bug 8002099 8006694
+ * @bug 8002099 8006694 8129962
  * @summary Add support for intersection types in cast expression
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../../lib
- * @modules jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm/timeout=360 IntersectionTypeCastTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+
+ * @run main IntersectionTypeCastTest
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import com.sun.tools.javac.util.List;
 
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-import com.sun.source.util.JavacTask;
-import com.sun.tools.javac.util.List;
-import com.sun.tools.javac.util.ListBuffer;
+import java.io.IOException;
 
-public class IntersectionTypeCastTest
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+public class IntersectionTypeCastTest extends ComboInstance<IntersectionTypeCastTest> {
 
-    interface Type {
+    interface Type extends ComboParameter {
         boolean subtypeOf(Type that);
-        String asString();
         boolean isClass();
         boolean isInterface();
     }
 
     enum InterfaceKind implements Type {
-        A("interface A { }\n", "A", null),
-        B("interface B { }\n", "B", null),
-        C("interface C extends A { }\n", "C", A);
+        A("A", null),
+        B("B", null),
+        C("C", A);
 
-        String declStr;
         String typeStr;
         InterfaceKind superInterface;
 
-        InterfaceKind(String declStr, String typeStr,
-                InterfaceKind superInterface) {
-            this.declStr = declStr;
+        InterfaceKind(String typeStr, InterfaceKind superInterface) {
             this.typeStr = typeStr;
             this.superInterface = superInterface;
         }
@@ -81,11 +75,6 @@
         }
 
         @Override
-        public String asString() {
-            return typeStr;
-        }
-
-        @Override
         public boolean isClass() {
             return false;
         }
@@ -94,42 +83,31 @@
         public boolean isInterface() {
             return true;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return typeStr;
+        }
     }
 
     enum ClassKind implements Type {
-        OBJECT(null, "Object"),
-        CA("#M class CA implements A { }\n", "CA",
-           InterfaceKind.A),
-        CB("#M class CB implements B { }\n", "CB",
-           InterfaceKind.B),
-        CAB("#M class CAB implements A, B { }\n", "CAB",
-            InterfaceKind.A, InterfaceKind.B),
-        CC("#M class CC implements C { }\n", "CC",
-           InterfaceKind.C, InterfaceKind.A),
-        CCA("#M class CCA implements C, A { }\n", "CCA",
-            InterfaceKind.C, InterfaceKind.A),
-        CCB("#M class CCB implements C, B { }\n", "CCB",
-            InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
-        CCAB("#M class CCAB implements C, A, B { }\n", "CCAB",
-             InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
+        OBJECT("Object"),
+        CA("CA", InterfaceKind.A),
+        CB("CB", InterfaceKind.B),
+        CAB("CAB", InterfaceKind.A, InterfaceKind.B),
+        CC("CC", InterfaceKind.C, InterfaceKind.A),
+        CCA("CCA", InterfaceKind.C, InterfaceKind.A),
+        CCB("CCB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
+        CCAB("CCAB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
 
-        String declTemplate;
         String typeStr;
         List<InterfaceKind> superInterfaces;
 
-        ClassKind(String declTemplate, String typeStr,
-                InterfaceKind... superInterfaces) {
-            this.declTemplate = declTemplate;
+        ClassKind(String typeStr, InterfaceKind... superInterfaces) {
             this.typeStr = typeStr;
             this.superInterfaces = List.from(superInterfaces);
         }
 
-        String getDecl(ModifierKind mod) {
-            return declTemplate != null ?
-                    declTemplate.replaceAll("#M", mod.modStr) :
-                    "";
-        }
-
         @Override
         public boolean subtypeOf(Type that) {
             return this == that || superInterfaces.contains(that) ||
@@ -137,11 +115,6 @@
         }
 
         @Override
-        public String asString() {
-            return typeStr;
-        }
-
-        @Override
         public boolean isClass() {
             return true;
         }
@@ -150,9 +123,14 @@
         public boolean isInterface() {
             return false;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return typeStr;
+        }
     }
 
-    enum ModifierKind {
+    enum ModifierKind implements ComboParameter {
         NONE(""),
         FINAL("final");
 
@@ -161,14 +139,18 @@
         ModifierKind(String modStr) {
             this.modStr = modStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return modStr;
+        }
     }
 
-    enum CastKind {
-        CLASS("(#C)", 0),
-        INTERFACE("(#I0)", 1),
-        INTERSECTION2("(#C & #I0)", 1),
-        INTERSECTION3("(#C & #I0 & #I1)", 2);
-        //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3);
+    enum CastKind implements ComboParameter {
+        CLASS("(#{CLAZZ#IDX})", 0),
+        INTERFACE("(#{INTF1#IDX})", 1),
+        INTERSECTION2("(#{CLAZZ#IDX} & #{INTF1#IDX})", 1),
+        INTERSECTION3("(#{CLAZZ#IDX} & #{INTF1#IDX} & #{INTF2#IDX})", 2);
 
         String castTemplate;
         int interfaceBounds;
@@ -177,6 +159,11 @@
             this.castTemplate = castTemplate;
             this.interfaceBounds = interfaceBounds;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return castTemplate.replaceAll("#IDX", optParameter);
+        }
     }
 
     static class CastInfo {
@@ -188,19 +175,9 @@
             this.types = types;
         }
 
-        String getCast() {
-            String temp = kind.castTemplate.replaceAll("#C",
-                    types[0].asString());
-            for (int i = 0; i < kind.interfaceBounds ; i++) {
-                temp = temp.replace(String.format("#I%d", i),
-                                    types[i + 1].asString());
-            }
-            return temp;
-        }
-
         boolean hasDuplicateTypes() {
-            for (int i = 0 ; i < types.length ; i++) {
-                for (int j = 0 ; j < types.length ; j++) {
+            for (int i = 0 ; i < arity() ; i++) {
+                for (int j = 0 ; j < arity() ; j++) {
                     if (i != j && types[i] == types[j]) {
                         return true;
                     }
@@ -210,8 +187,10 @@
         }
 
         boolean compatibleWith(ModifierKind mod, CastInfo that) {
-            for (Type t1 : types) {
-                for (Type t2 : that.types) {
+            for (int i = 0 ; i < arity() ; i++) {
+                Type t1 = types[i];
+                for (int j = 0 ; j < that.arity() ; j++) {
+                    Type t2 = that.types[j];
                     boolean compat =
                             t1.subtypeOf(t2) ||
                             t2.subtypeOf(t1) ||
@@ -223,138 +202,92 @@
             }
             return true;
         }
+
+        private int arity() {
+            return kind.interfaceBounds + 1;
+        }
     }
 
     public static void main(String... args) throws Exception {
-        for (ModifierKind mod : ModifierKind.values()) {
-            for (CastInfo cast1 : allCastInfo()) {
-                for (CastInfo cast2 : allCastInfo()) {
-                    pool.execute(
-                        new IntersectionTypeCastTest(mod, cast1, cast2));
+        new ComboTestHelper<IntersectionTypeCastTest>()
+                .withFilter(IntersectionTypeCastTest::isRedundantCast)
+                .withFilter(IntersectionTypeCastTest::arityFilter)
+                .withArrayDimension("CAST", (x, ck, idx) -> x.castKinds[idx] = ck, 2, CastKind.values())
+                .withDimension("CLAZZ1", (x, ty) -> x.types1[0] = ty, ClassKind.values())
+                .withDimension("INTF11", (x, ty) -> x.types1[1] = ty, InterfaceKind.values())
+                .withDimension("INTF21", (x, ty) -> x.types1[2] = ty, InterfaceKind.values())
+                .withDimension("CLAZZ2", (x, ty) -> x.types2[0] = ty, ClassKind.values())
+                .withDimension("INTF12", (x, ty) -> x.types2[1] = ty, InterfaceKind.values())
+                .withDimension("INTF22", (x, ty) -> x.types2[2] = ty, InterfaceKind.values())
+                .withDimension("MOD", (x, mod) -> x.mod = mod, ModifierKind.values())
+                .run(IntersectionTypeCastTest::new);
+    }
+
+    boolean isRedundantCast() {
+        for (int i = 0 ; i < 2 ; i++) {
+            Type[] types = i == 0 ? types1 : types2;
+            if (castKinds[i] == CastKind.INTERFACE && types[0] != ClassKind.OBJECT) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    boolean arityFilter() {
+        for (int i = 0 ; i < 2 ; i++) {
+            int lastPos = castKinds[i].interfaceBounds + 1;
+            Type[] types = i == 0 ? types1 : types2;
+            for (int j = 1; j < types.length; j++) {
+                boolean shouldBeSet = j < lastPos;
+                if (!shouldBeSet && (types[j] != InterfaceKind.A)) {
+                    return false;
                 }
             }
         }
-        checkAfterExec();
-    }
-
-    static List<CastInfo> allCastInfo() {
-        ListBuffer<CastInfo> buf = new ListBuffer<>();
-        for (CastKind kind : CastKind.values()) {
-            for (ClassKind clazz : ClassKind.values()) {
-                if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) {
-                    continue;
-                } else if (kind.interfaceBounds == 0) {
-                    buf.append(new CastInfo(kind, clazz));
-                    continue;
-                } else {
-                    for (InterfaceKind intf1 : InterfaceKind.values()) {
-                        if (kind.interfaceBounds == 1) {
-                            buf.append(new CastInfo(kind, clazz, intf1));
-                            continue;
-                        } else {
-                            for (InterfaceKind intf2 : InterfaceKind.values()) {
-                                if (kind.interfaceBounds == 2) {
-                                    buf.append(
-                                            new CastInfo(kind, clazz, intf1, intf2));
-                                    continue;
-                                } else {
-                                    for (InterfaceKind intf3 : InterfaceKind.values()) {
-                                        buf.append(
-                                                new CastInfo(kind, clazz, intf1,
-                                                             intf2, intf3));
-                                        continue;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        return buf.toList();
+        return true;
     }
 
     ModifierKind mod;
-    CastInfo cast1, cast2;
-    JavaSource source;
-    DiagnosticChecker diagChecker;
-
-    IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) {
-        this.mod = mod;
-        this.cast1 = cast1;
-        this.cast2 = cast2;
-        this.source = new JavaSource();
-        this.diagChecker = new DiagnosticChecker();
-    }
+    CastKind[] castKinds = new CastKind[2];
+    Type[] types1 = new Type[3];
+    Type[] types2 = new Type[3];
 
     @Override
-    public void run() {
-        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
-
-        JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker,
-                null, null, Arrays.asList(source));
-        try {
-            ct.analyze();
-        } catch (Throwable ex) {
-            throw new AssertionError("Error thrown when compiling the following code:\n" +
-                    source.getCharContent(true));
-        }
-        check();
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withSourceFromTemplate(bodyTemplate)
+                .analyze());
     }
 
-    class JavaSource extends SimpleJavaFileObject {
-
-        String bodyTemplate = "class Test {\n" +
-                              "   void test() {\n" +
-                              "      Object o = #C1#C2null;\n" +
-                              "   } }";
-
-        String source = "";
+    String bodyTemplate = "class Test {\n" +
+                          "   void test() {\n" +
+                          "      Object o = #{CAST[0].1}#{CAST[1].2}null;\n" +
+                          "   } }\n" +
+                          "interface A { }\n" +
+                          "interface B { }\n" +
+                          "interface C extends A { }\n" +
+                          "#{MOD} class CA implements A { }\n" +
+                          "#{MOD} class CB implements B { }\n" +
+                          "#{MOD} class CAB implements A, B { }\n" +
+                          "#{MOD} class CC implements C { }\n" +
+                          "#{MOD} class CCA implements C, A { }\n" +
+                          "#{MOD} class CCB implements C, B { }\n" +
+                          "#{MOD} class CCAB implements C, A, B { }";
 
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            for (ClassKind ck : ClassKind.values()) {
-                source += ck.getDecl(mod);
-            }
-            for (InterfaceKind ik : InterfaceKind.values()) {
-                source += ik.declStr;
-            }
-            source += bodyTemplate.replaceAll("#C1", cast1.getCast()).
-                    replaceAll("#C2", cast2.getCast());
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
-    }
-
-    void check() {
-        checkCount.incrementAndGet();
-
+    void check(Result<?> res) {
+        CastInfo cast1 = new CastInfo(castKinds[0], types1);
+        CastInfo cast2 = new CastInfo(castKinds[1], types2);
         boolean errorExpected = cast1.hasDuplicateTypes() ||
                 cast2.hasDuplicateTypes();
 
         errorExpected |= !cast2.compatibleWith(mod, cast1);
 
-        if (errorExpected != diagChecker.errorFound) {
-            throw new Error("invalid diagnostics for source:\n" +
-                source.getCharContent(true) +
-                "\nFound error: " + diagChecker.errorFound +
+        boolean errorsFound = res.hasErrors();
+        if (errorExpected != errorsFound) {
+            fail("invalid diagnostics for source:\n" +
+                res.compilationInfo() +
+                "\nFound error: " + errorsFound +
                 "\nExpected error: " + errorExpected);
         }
     }
-
-    static class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean errorFound;
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errorFound = true;
-            }
-        }
-    }
-
 }
--- a/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,40 +23,41 @@
 
 /*
  * @test
- * @bug 8005166
+ * @bug 8005166 8129962
  * @summary Add support for static interface methods
  *          Smoke test for static interface method hiding
- * @modules jdk.compiler
- * @run main/timeout=600 InterfaceMethodHidingTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main InterfaceMethodHidingTest
  */
 
-import com.sun.source.util.JavacTask;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.StandardJavaFileManager;
-import javax.tools.ToolProvider;
+import java.io.IOException;
+
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-
-public class InterfaceMethodHidingTest {
-
-    static int checkCount = 0;
+public class InterfaceMethodHidingTest extends ComboInstance<InterfaceMethodHidingTest> {
 
-    enum SignatureKind {
-        VOID_INTEGER("void m(Integer s)", "return;"),
-        STRING_INTEGER("String m(Integer s)", "return null;"),
-        VOID_STRING("void m(String s)", "return;"),
-        STRING_STRING("String m(String s)", "return null;");
+    enum SignatureKind implements ComboParameter {
+        VOID_INTEGER("void m(Integer s)", false),
+        STRING_INTEGER("String m(Integer s)", true),
+        VOID_STRING("void m(String s)", false),
+        STRING_STRING("String m(String s)", true);
 
         String sigStr;
-        String retStr;
+        boolean needsReturn;
 
-        SignatureKind(String sigStr, String retStr) {
+        SignatureKind(String sigStr, boolean needsReturn) {
             this.sigStr = sigStr;
-            this.retStr = retStr;
+            this.needsReturn = needsReturn;
         }
 
         boolean overrideEquivalentWith(SignatureKind s2) {
@@ -71,18 +72,21 @@
                     throw new AssertionError("bad signature kind");
             }
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return sigStr;
+        }
     }
 
-    enum MethodKind {
-        VIRTUAL("", "#M #S;"),
-        STATIC("static", "#M #S { #BE; #R }"),
-        DEFAULT("default", "#M #S { #BE; #R }");
+    enum MethodKind implements ComboParameter {
+        VIRTUAL("#{SIG[#IDX]};"),
+        STATIC("static #{SIG[#IDX]} { #{BODY[#IDX]}; #{RET.#IDX} }"),
+        DEFAULT("default #{SIG[#IDX]} { #{BODY[#IDX]}; #{RET.#IDX} }");
 
-        String modStr;
         String methTemplate;
 
-        MethodKind(String modStr, String methTemplate) {
-            this.modStr = modStr;
+        MethodKind(String methTemplate) {
             this.methTemplate = methTemplate;
         }
 
@@ -96,15 +100,13 @@
                     mk1 != STATIC;
         }
 
-        String getBody(BodyExpr be, SignatureKind sk) {
-            return methTemplate.replaceAll("#BE", be.bodyExprStr)
-                    .replaceAll("#R", sk.retStr)
-                    .replaceAll("#M", modStr)
-                    .replaceAll("#S", sk.sigStr);
+        @Override
+        public String expand(String optParameter) {
+            return methTemplate.replaceAll("#IDX", optParameter);
         }
     }
 
-    enum BodyExpr {
+    enum BodyExpr implements ComboParameter {
         NONE(""),
         THIS("Object o = this");
 
@@ -118,129 +120,78 @@
             return this == NONE ||
                     mk != MethodKind.STATIC;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return bodyExprStr;
+        }
     }
 
     public static void main(String... args) throws Exception {
-
-        //create default shared JavaCompiler - reused across multiple compilations
-        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
-        try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
-
-            for (MethodKind mk1 : MethodKind.values()) {
-                for (SignatureKind sk1 : SignatureKind.values()) {
-                    for (BodyExpr be1 : BodyExpr.values()) {
-                        for (MethodKind mk2 : MethodKind.values()) {
-                            for (SignatureKind sk2 : SignatureKind.values()) {
-                                for (BodyExpr be2 : BodyExpr.values()) {
-                                    for (MethodKind mk3 : MethodKind.values()) {
-                                        for (SignatureKind sk3 : SignatureKind.values()) {
-                                            for (BodyExpr be3 : BodyExpr.values()) {
-                                                new InterfaceMethodHidingTest(mk1, mk2, mk3, sk1, sk2, sk3, be1, be2, be3).run(comp, fm);
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            System.out.println("Total check executed: " + checkCount);
-        }
+        new ComboTestHelper<InterfaceMethodHidingTest>()
+                .withArrayDimension("SIG", (x, sig, idx) -> x.signatureKinds[idx] = sig, 3, SignatureKind.values())
+                .withArrayDimension("BODY", (x, body, idx) -> x.bodyExprs[idx] = body, 3, BodyExpr.values())
+                .withArrayDimension("MET", (x, meth, idx) -> x.methodKinds[idx] = meth, 3, MethodKind.values())
+                .run(InterfaceMethodHidingTest::new);
     }
 
-    MethodKind mk1, mk2, mk3;
-    SignatureKind sk1, sk2, sk3;
-    BodyExpr be1, be2, be3;
-    JavaSource source;
-    DiagnosticChecker diagChecker;
+    MethodKind[] methodKinds = new MethodKind[3];
+    SignatureKind[] signatureKinds = new SignatureKind[3];
+    BodyExpr[] bodyExprs = new BodyExpr[3];
 
-    InterfaceMethodHidingTest(MethodKind mk1, MethodKind mk2, MethodKind mk3,
-            SignatureKind sk1, SignatureKind sk2, SignatureKind sk3, BodyExpr be1, BodyExpr be2, BodyExpr be3) {
-        this.mk1 = mk1;
-        this.mk2 = mk2;
-        this.mk3 = mk3;
-        this.sk1 = sk1;
-        this.sk2 = sk2;
-        this.sk3 = sk3;
-        this.be1 = be1;
-        this.be2 = be2;
-        this.be3 = be3;
-        this.source = new JavaSource();
-        this.diagChecker = new DiagnosticChecker();
-    }
-
-    class JavaSource extends SimpleJavaFileObject {
-
-        String template = "interface Sup {\n" +
+    String template = "interface Sup {\n" +
                           "   default void sup() { }\n" +
                           "}\n" +
                           "interface A extends Sup {\n" +
-                          "   #M1\n" +
+                          "   #{MET[0].0}\n" +
                           "}\n" +
                           "interface B extends A, Sup {\n" +
-                          "   #M2\n" +
+                          "   #{MET[1].1}\n" +
                           "}\n" +
                           "interface C extends B, Sup {\n" +
-                          "   #M3\n" +
+                          "   #{MET[2].2}\n" +
                           "}\n";
 
-        String source;
+    @Override
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withOption("-XDallowStaticInterfaceMethods")
+                .withSourceFromTemplate(template, this::returnExpr)
+                .analyze());
+    }
 
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = template.replaceAll("#M1", mk1.getBody(be1, sk1))
-                    .replaceAll("#M2", mk2.getBody(be2, sk2))
-                    .replaceAll("#M3", mk3.getBody(be3, sk3));
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
+    ComboParameter returnExpr(String name) {
+        switch (name) {
+            case "RET":
+                return optParameter -> {
+                    int idx = new Integer(optParameter);
+                    return signatureKinds[idx].needsReturn ? "return null;" : "return;";
+                };
+            default:
+                return null;
         }
     }
 
-    void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
-        JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
-                Arrays.asList("-XDallowStaticInterfaceMethods"), null, Arrays.asList(source));
-        try {
-            ct.analyze();
-        } catch (Throwable ex) {
-            throw new AssertionError("Error thrown when analyzing the following source:\n" + source.getCharContent(true));
-        }
-        check();
-    }
+    void check(Result<?> res) {
+        boolean errorExpected = !bodyExprs[0].allowed(methodKinds[0]) ||
+                !bodyExprs[1].allowed(methodKinds[1]) ||
+                !bodyExprs[2].allowed(methodKinds[2]);
 
-    void check() {
-        boolean errorExpected =
-                !be1.allowed(mk1) || !be2.allowed(mk2) || !be3.allowed(mk3);
-
-        if (mk1.inherithed()) {
-            errorExpected |=
-                    sk2.overrideEquivalentWith(sk1) && !MethodKind.overrides(mk2, sk2, mk1, sk1) ||
-                    sk3.overrideEquivalentWith(sk1) && !MethodKind.overrides(mk3, sk3, mk1, sk1);
+        if (methodKinds[0].inherithed()) {
+            errorExpected |= signatureKinds[1].overrideEquivalentWith(signatureKinds[0]) &&
+                    !MethodKind.overrides(methodKinds[1], signatureKinds[1], methodKinds[0], signatureKinds[0]) ||
+                    signatureKinds[2].overrideEquivalentWith(signatureKinds[0]) &&
+                    !MethodKind.overrides(methodKinds[2], signatureKinds[2], methodKinds[0], signatureKinds[0]);
         }
 
-        if (mk2.inherithed()) {
-            errorExpected |=
-                    sk3.overrideEquivalentWith(sk2) && !MethodKind.overrides(mk3, sk3, mk2, sk2);
+        if (methodKinds[1].inherithed()) {
+            errorExpected |= signatureKinds[2].overrideEquivalentWith(signatureKinds[1]) &&
+                    !MethodKind.overrides(methodKinds[2], signatureKinds[2], methodKinds[1], signatureKinds[1]);
         }
 
-        checkCount++;
-        if (diagChecker.errorFound != errorExpected) {
-            throw new AssertionError("Problem when compiling source:\n" + source.getCharContent(true) +
-                    "\nfound error: " + diagChecker.errorFound);
-        }
-    }
-
-    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean errorFound;
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errorFound = true;
-            }
+        if (res.hasErrors() != errorExpected) {
+            fail("Problem when compiling source:\n" + res.compilationInfo() +
+                    "\nfound error: " + res.hasErrors());
         }
     }
 }
--- a/langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,33 +23,32 @@
 
 /*
  * @test
- * @bug 7192246 8006694
+ * @bug 7192246 8006694 8129962
  * @summary Automatic test for checking correctness of default super/this resolution
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm TestDefaultSuperCall
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main TestDefaultSuperCall
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import java.net.URI;
-import java.util.Arrays;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-
-import com.sun.source.util.JavacTask;
 
-public class TestDefaultSuperCall
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-    enum InterfaceKind {
+public class TestDefaultSuperCall extends ComboInstance<TestDefaultSuperCall> {
+
+    enum InterfaceKind implements ComboParameter {
         DEFAULT("interface A extends B { default void m() { } }"),
         ABSTRACT("interface A extends B { void m(); }"),
         NONE("interface A extends B { }");
@@ -63,9 +62,14 @@
         boolean methodDefined() {
             return this == DEFAULT;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return interfaceStr;
+        }
     }
 
-    enum PruneKind {
+    enum PruneKind implements ComboParameter {
         NO_PRUNE("interface C { }"),
         PRUNE("interface C extends A { }");
 
@@ -79,15 +83,20 @@
         PruneKind(String interfaceStr) {
             this.interfaceStr = interfaceStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return interfaceStr;
+        }
     }
 
-    enum QualifierKind {
+    enum QualifierKind implements ComboParameter {
         DIRECT_1("C"),
         DIRECT_2("A"),
         INDIRECT("B"),
         UNRELATED("E"),
-        ENCLOSING_1(null),
-        ENCLOSING_2(null);
+        ENCLOSING_1("name0"),
+        ENCLOSING_2("name1");
 
         String qualifierStr;
 
@@ -95,15 +104,6 @@
             this.qualifierStr = qualifierStr;
         }
 
-        String getQualifier(Shape sh) {
-            switch (this) {
-                case ENCLOSING_1: return sh.enclosingAt(0);
-                case ENCLOSING_2: return sh.enclosingAt(1);
-                default:
-                    return qualifierStr;
-            }
-        }
-
         boolean isEnclosing() {
             return this == ENCLOSING_1 ||
                     this == ENCLOSING_2;
@@ -119,9 +119,14 @@
                     return false;
             }
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return qualifierStr;
+        }
     }
 
-    enum ExprKind {
+    enum ExprKind implements ComboParameter {
         THIS("this"),
         SUPER("super");
 
@@ -130,19 +135,24 @@
         ExprKind(String exprStr) {
             this.exprStr = exprStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return exprStr;
+        }
     }
 
-    enum ElementKind {
-        INTERFACE("interface #N { #B }", true),
-        INTERFACE_EXTENDS("interface #N extends A, C { #B }", true),
-        CLASS("class #N { #B }", false),
-        CLASS_EXTENDS("abstract class #N implements A, C { #B }", false),
-        STATIC_CLASS("static class #N { #B }", true),
-        STATIC_CLASS_EXTENDS("abstract static class #N implements A, C { #B }", true),
-        ANON_CLASS("new Object() { #B };", false),
-        METHOD("void test() { #B }", false),
-        STATIC_METHOD("static void test() { #B }", true),
-        DEFAULT_METHOD("default void test() { #B }", false);
+    enum ElementKind implements ComboParameter {
+        INTERFACE("interface name#CURR { #BODY }", true),
+        INTERFACE_EXTENDS("interface name#CURR extends A, C { #BODY }", true),
+        CLASS("class name#CURR { #BODY }", false),
+        CLASS_EXTENDS("abstract class name#CURR implements A, C { #BODY }", false),
+        STATIC_CLASS("static class name#CURR { #BODY }", true),
+        STATIC_CLASS_EXTENDS("abstract static class name#CURR implements A, C { #BODY }", true),
+        ANON_CLASS("new Object() { #BODY };", false),
+        METHOD("void test() { #BODY }", false),
+        STATIC_METHOD("static void test() { #BODY }", true),
+        DEFAULT_METHOD("default void test() { #BODY }", false);
 
         String templateDecl;
         boolean isStatic;
@@ -207,11 +217,21 @@
                     this == STATIC_CLASS_EXTENDS ||
                     this == CLASS_EXTENDS;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            int nextDepth = new Integer(optParameter) + 1;
+            String replStr = (nextDepth <= 4) ?
+                    String.format("#{ELEM[%d].%d}", nextDepth, nextDepth) :
+                    "#{QUAL}.#{EXPR}.#{METH}();";
+            return templateDecl
+                    .replaceAll("#CURR", optParameter)
+                    .replaceAll("#BODY", replStr);
+        }
     }
 
     static class Shape {
 
-        String shapeStr;
         List<ElementKind> enclosingElements;
         List<String> enclosingNames;
         List<String> elementsWithMethod;
@@ -234,114 +254,73 @@
                 } else {
                     elementsWithMethod.add(prevName);
                 }
-                String element = ek.templateDecl.replaceAll("#N", name);
-                shapeStr = shapeStr ==
-                        null ? element : shapeStr.replaceAll("#B", element);
                 prevName = name;
             }
         }
-
-        String getShape(QualifierKind qk, ExprKind ek) {
-            String methName = ek == ExprKind.THIS ? "test" : "m";
-            String call = qk.getQualifier(this) + "." +
-                    ek.exprStr + "." + methName + "();";
-            return shapeStr.replaceAll("#B", call);
-        }
-
-        String enclosingAt(int index) {
-            return index < enclosingNames.size() ?
-                    enclosingNames.get(index) : "BAD";
-        }
     }
 
     public static void main(String... args) throws Exception {
-        for (InterfaceKind ik : InterfaceKind.values()) {
-            for (PruneKind pk : PruneKind.values()) {
-                for (ElementKind ek1 : ElementKind.values()) {
-                    if (!ek1.isAllowedTop()) continue;
-                    for (ElementKind ek2 : ElementKind.values()) {
-                        if (!ek2.isAllowedEnclosing(ek1, true)) continue;
-                        for (ElementKind ek3 : ElementKind.values()) {
-                            if (!ek3.isAllowedEnclosing(ek2, false)) continue;
-                            for (ElementKind ek4 : ElementKind.values()) {
-                                if (!ek4.isAllowedEnclosing(ek3, false)) continue;
-                                for (ElementKind ek5 : ElementKind.values()) {
-                                    if (!ek5.isAllowedEnclosing(ek4, false) ||
-                                            ek5.isClassDecl()) continue;
-                                    for (QualifierKind qk : QualifierKind.values()) {
-                                        for (ExprKind ek : ExprKind.values()) {
-                                            pool.execute(
-                                                    new TestDefaultSuperCall(ik, pk,
-                                                    new Shape(ek1, ek2, ek3,
-                                                    ek4, ek5), qk, ek));
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec();
+        new ComboTestHelper<TestDefaultSuperCall>()
+                .withFilter(TestDefaultSuperCall::filterBadTopElement)
+                .withFilter(TestDefaultSuperCall::filterBadIntermediateElement)
+                .withFilter(TestDefaultSuperCall::filterBadTerminalElement)
+                .withDimension("INTF1", (x, ik) -> x.ik = ik, InterfaceKind.values())
+                .withDimension("INTF2", (x, pk) -> x.pk = pk, PruneKind.values())
+                .withArrayDimension("ELEM", (x, elem, idx) -> x.elements[idx] = elem, 5, ElementKind.values())
+                .withDimension("QUAL", (x, qk) -> x.qk = qk, QualifierKind.values())
+                .withDimension("EXPR", (x, ek) -> x.ek = ek, ExprKind.values())
+                .run(TestDefaultSuperCall::new);
     }
 
     InterfaceKind ik;
     PruneKind pk;
-    Shape sh;
+    ElementKind[] elements = new ElementKind[5];
     QualifierKind qk;
     ExprKind ek;
-    JavaSource source;
-    DiagnosticChecker diagChecker;
+
+    boolean filterBadTopElement() {
+        return elements[0].isAllowedTop();
+    }
 
-    TestDefaultSuperCall(InterfaceKind ik, PruneKind pk, Shape sh,
-            QualifierKind qk, ExprKind ek) {
-        this.ik = ik;
-        this.pk = pk;
-        this.sh = sh;
-        this.qk = qk;
-        this.ek = ek;
-        this.source = new JavaSource();
-        this.diagChecker = new DiagnosticChecker();
+    boolean filterBadIntermediateElement() {
+        for (int i = 1 ; i < 4 ; i++) {
+            if (!elements[i].isAllowedEnclosing(elements[i - 1], i == 1)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    boolean filterBadTerminalElement() {
+        return elements[4].isAllowedEnclosing(elements[3], false) && !elements[4].isClassDecl();
     }
 
-    class JavaSource extends SimpleJavaFileObject {
-
-        String template = "interface E {}\n" +
-                          "interface B { }\n" +
-                          "#I\n" +
-                          "#P\n" +
-                          "#C";
-
-        String source;
+    String template = "interface E {}\n" +
+                      "interface B { }\n" +
+                      "#{INTF1}\n" +
+                      "#{INTF2}\n" +
+                      "#{ELEM[0].0}";
 
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = template.replaceAll("#I", ik.interfaceStr)
-                    .replaceAll("#P", pk.interfaceStr)
-                    .replaceAll("#C", sh.getShape(qk, ek));
-        }
+    @Override
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withSourceFromTemplate(template, this::methodName)
+                .analyze());
+    }
 
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
+    ComboParameter methodName(String parameterName) {
+        switch (parameterName) {
+            case "METH":
+                String methodName = ek == ExprKind.THIS ? "test" : "m";
+                return new ComboParameter.Constant<String>(methodName);
+            default:
+                return null;
         }
     }
 
-    public void run() {
-        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
-                null, null, Arrays.asList(source));
-        try {
-            ct.analyze();
-        } catch (Throwable ex) {
-            processException(ex);
-            return;
-        }
-        check();
-    }
+    void check(Result<?> res) {
+        Shape sh = new Shape(elements);
 
-    void check() {
         boolean errorExpected = false;
 
         boolean badEnclosing = false;
@@ -364,7 +343,7 @@
             boolean found = false;
             for (int i = 0; i < sh.enclosingElements.size(); i++) {
                 if (sh.enclosingElements.get(i) == ElementKind.ANON_CLASS) continue;
-                if (sh.enclosingNames.get(i).equals(qk.getQualifier(sh))) {
+                if (sh.enclosingNames.get(i).equals(qk.qualifierStr)) {
                     found = sh.elementsWithMethod.contains(sh.enclosingNames.get(i));
                     break;
                 }
@@ -388,10 +367,9 @@
             }
         }
 
-        checkCount.incrementAndGet();
-        if (diagChecker.errorFound != errorExpected) {
-            throw new AssertionError("Problem when compiling source:\n" +
-                    source.getCharContent(true) +
+        if (res.hasErrors() != errorExpected) {
+            fail("Problem when compiling source:\n" +
+                    res.compilationInfo() +
                     "\nenclosingElems: " + sh.enclosingElements +
                     "\nenclosingNames: " + sh.enclosingNames +
                     "\nelementsWithMethod: " + sh.elementsWithMethod +
@@ -399,20 +377,7 @@
                     "\nbad this: " + badThis +
                     "\nbad super: " + badSuper +
                     "\nqual kind: " + qk +
-                    "\nfound error: " + diagChecker.errorFound);
+                    "\nfound error: " + res.hasErrors());
         }
     }
-
-    static class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean errorFound;
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errorFound = true;
-            }
-        }
-    }
-
 }
--- a/langtools/test/tools/javac/failover/CheckAttributedTree.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/failover/CheckAttributedTree.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6970584 8006694 8062373
+ * @bug 6970584 8006694 8062373 8129962
  * @summary assorted position errors in compiler syntax trees
  *  temporarily workaround combo tests are causing time out in several platforms
  * @library ../lib
@@ -31,13 +31,10 @@
  *          jdk.compiler/com.sun.tools.javac.code
  *          jdk.compiler/com.sun.tools.javac.tree
  *          jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm CheckAttributedTree -q -r -et ERRONEOUS .
+ * @build combo.ComboTestHelper
+ * @run main CheckAttributedTree -q -r -et ERRONEOUS .
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
@@ -56,6 +53,11 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.lang.reflect.Field;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -79,18 +81,14 @@
 import javax.swing.text.BadLocationException;
 import javax.swing.text.DefaultHighlighter;
 import javax.swing.text.Highlighter;
-import javax.tools.Diagnostic;
-import javax.tools.DiagnosticListener;
 import javax.tools.JavaFileObject;
 
 import com.sun.source.tree.CompilationUnitTree;
-import com.sun.source.util.JavacTask;
 import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskEvent.Kind;
 import com.sun.source.util.TaskListener;
-import com.sun.tools.javac.api.JavacTaskImpl;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.main.JavaCompiler;
 import com.sun.tools.javac.tree.EndPosTable;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
@@ -101,6 +99,10 @@
 
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
+import combo.ComboTestHelper;
+import combo.ComboInstance;
+import combo.ComboTestHelper.IgnoreMode;
+
 /**
  * Utility and test program to check validity of tree positions for tree nodes.
  * The program can be run standalone, or as a jtreg test.  In standalone mode,
@@ -113,7 +115,7 @@
  * covering any new language features that may be tested in this test suite.
  */
 
-public class CheckAttributedTree extends JavacTestingAbstractThreadedTest {
+public class CheckAttributedTree {
     /**
      * Main entry point.
      * If test.src is set, program runs in jtreg mode, and will throw an Error
@@ -125,7 +127,6 @@
     public static void main(String... args) throws Exception {
         String testSrc = System.getProperty("test.src");
         File baseDir = (testSrc == null) ? null : new File(testSrc);
-        throwAssertionOnError = false;
         boolean ok = new CheckAttributedTree().run(baseDir, args);
         if (!ok) {
             if (testSrc != null)  // jtreg mode
@@ -160,7 +161,6 @@
                 quiet = true;
             else if (arg.equals("-v")) {
                 verbose = true;
-                printAll = true;
             }
             else if (arg.equals("-t") && i + 1 < args.length)
                 tags.add(args[++i]);
@@ -187,18 +187,37 @@
             }
         }
 
-        for (File file: files) {
-            if (file.exists())
-                test(file);
-            else
-                error("File not found: " + file);
-        }
+        ComboTestHelper<FileChecker> cth = new ComboTestHelper<>();
+        cth.withIgnoreMode(IgnoreMode.IGNORE_ALL)
+                .withFilter(FileChecker::checkFile)
+                .withDimension("FILE", (x, file) -> x.file = file, getAllFiles(files))
+                .run(FileChecker::new);
 
         if (fileCount.get() != 1)
             errWriter.println(fileCount + " files read");
-        checkAfterExec(false);
+
+        if (verbose) {
+            System.out.println(errSWriter.toString());
+        }
+
+        return (gui || !cth.info().hasFailures());
+    }
 
-        return (gui || errCount.get() == 0);
+    File[] getAllFiles(List<File> roots) throws IOException {
+        long now = System.currentTimeMillis();
+        ArrayList<File> buf = new ArrayList<>();
+        for (File file : roots) {
+            Files.walkFileTree(file.toPath(), new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                    buf.add(file.toFile());
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        }
+        long delta = System.currentTimeMillis() - now;
+        System.err.println("All files = " + buf.size() + " " + delta);
+        return buf.toArray(new File[buf.size()]);
     }
 
     /**
@@ -224,116 +243,217 @@
         out.println("");
     }
 
-    /**
-     * Test a file. If the file is a directory, it will be recursively scanned
-     * for java files.
-     * @param file the file or directory to test
-     */
-    void test(final File file) {
-        if (excludeFiles.contains(file)) {
-            if (!quiet)
-                error("File " + file + " excluded");
-            return;
+    class FileChecker extends ComboInstance<FileChecker> {
+
+        File file;
+
+        boolean checkFile() {
+            if (!file.exists()) {
+                error("File not found: " + file);
+                return false;
+            }
+            if (excludeFiles.contains(file)) {
+                if (!quiet)
+                    error("File " + file + " excluded");
+                return false;
+            }
+            if (!file.getName().endsWith(".java")) {
+                if (!quiet)
+                    error("File " + file + " ignored");
+                return false;
+            }
+
+            return true;
         }
 
-        if (file.isDirectory()) {
-            for (File f: file.listFiles()) {
-                test(f);
+        public void doWork() {
+            if (!file.exists()) {
+                error("File not found: " + file);
+            }
+            if (excludeFiles.contains(file)) {
+                if (!quiet)
+                    error("File " + file + " excluded");
+                return;
+            }
+            if (!file.getName().endsWith(".java")) {
+                if (!quiet)
+                    error("File " + file + " ignored");
+            }
+            try {
+                if (verbose)
+                    errWriter.println(file);
+                fileCount.incrementAndGet();
+                NPETester p = new NPETester();
+                p.test(read(file));
+            } catch (AttributionException e) {
+                if (!quiet) {
+                    error("Error attributing " + file + "\n" + e.getMessage());
+                }
+            } catch (IOException e) {
+                error("Error reading " + file + ": " + e);
             }
-            return;
+        }
+
+        /**
+         * Read a file.
+         * @param file the file to be read
+         * @return the tree for the content of the file
+         * @throws IOException if any IO errors occur
+         * @throws AttributionException if any errors occur while analyzing the file
+         */
+        List<Pair<JCCompilationUnit, JCTree>> read(File file) throws IOException, AttributionException {
+            try {
+                Iterable<? extends JavaFileObject> files = fileManager().getJavaFileObjects(file);
+                final List<Element> analyzedElems = new ArrayList<>();
+                final List<CompilationUnitTree> trees = new ArrayList<>();
+                Iterable<? extends Element> elems = newCompilationTask()
+                    .withWriter(pw)
+                        .withOption("-XDshouldStopPolicy=ATTR")
+                        .withOption("-XDverboseCompilePolicy")
+                        .withSource(files.iterator().next())
+                        .withListener(new TaskListener() {
+                            public void started(TaskEvent e) {
+                                if (e.getKind() == TaskEvent.Kind.ANALYZE)
+                                analyzedElems.add(e.getTypeElement());
+                        }
+
+                        public void finished(TaskEvent e) {
+                            if (e.getKind() == Kind.PARSE)
+                                trees.add(e.getCompilationUnit());
+                        }
+                    }).analyze().get();
+                if (!elems.iterator().hasNext())
+                    throw new AttributionException("No results from analyze");
+                List<Pair<JCCompilationUnit, JCTree>> res = new ArrayList<>();
+                for (CompilationUnitTree t : trees) {
+                   JCCompilationUnit cu = (JCCompilationUnit)t;
+                   for (JCTree def : cu.defs) {
+                       if (def.hasTag(CLASSDEF) &&
+                               analyzedElems.contains(((JCTree.JCClassDecl)def).sym)) {
+                           res.add(new Pair<>(cu, def));
+                       }
+                   }
+                }
+                return res;
+            }
+            catch (Throwable t) {
+                throw new AttributionException("Exception while attributing file: " + file);
+            }
         }
 
-        if (file.isFile() && file.getName().endsWith(".java")) {
-            pool.execute(new Runnable() {
-                @Override
-                public void run() {
+        /**
+         * Report an error. When the program is complete, the program will either
+         * exit or throw an Error if any errors have been reported.
+         * @param msg the error message
+         */
+        void error(String msg) {
+            System.err.println();
+            System.err.println(msg);
+            System.err.println();
+            fail(msg);
+        }
+
+        /**
+         * Main class for testing assertions concerning types/symbol
+         * left uninitialized after attribution
+         */
+        private class NPETester extends TreeScanner {
+            void test(List<Pair<JCCompilationUnit, JCTree>> trees) {
+                for (Pair<JCCompilationUnit, JCTree> p : trees) {
+                    sourcefile = p.fst.sourcefile;
+                    endPosTable = p.fst.endPositions;
+                    encl = new Info(p.snd, endPosTable);
+                    p.snd.accept(this);
+                }
+            }
+
+            @Override
+            public void scan(JCTree tree) {
+                if (tree == null ||
+                        excludeTags.contains(treeUtil.nameFromTag(tree.getTag()))) {
+                    return;
+                }
+
+                Info self = new Info(tree, endPosTable);
+                if (mandatoryType(tree)) {
+                    check(tree.type != null,
+                            "'null' field 'type' found in tree ", self);
+                    if (tree.type==null)
+                        Thread.dumpStack();
+                }
+
+                Field errField = checkFields(tree);
+                if (errField!=null) {
+                    check(false,
+                            "'null' field '" + errField.getName() + "' found in tree ", self);
+                }
+
+                Info prevEncl = encl;
+                encl = self;
+                tree.accept(this);
+                encl = prevEncl;
+            }
+
+            private boolean mandatoryType(JCTree that) {
+                return that instanceof JCTree.JCExpression ||
+                        that.hasTag(VARDEF) ||
+                        that.hasTag(METHODDEF) ||
+                        that.hasTag(CLASSDEF);
+            }
+
+            private final List<String> excludedFields = Arrays.asList("varargsElement", "targetType");
+
+            void check(boolean ok, String label, Info self) {
+                if (!ok) {
+                    if (gui) {
+                        if (viewer == null)
+                            viewer = new Viewer();
+                        viewer.addEntry(sourcefile, label, encl, self);
+                    }
+                    error(label + self.toString() + " encl: " + encl.toString() +
+                            " in file: " + sourcefile + "  " + self.tree);
+                }
+            }
+
+            Field checkFields(JCTree t) {
+                List<Field> fieldsToCheck = treeUtil.getFieldsOfType(t,
+                        excludedFields,
+                        Symbol.class,
+                        Type.class);
+                for (Field f : fieldsToCheck) {
                     try {
-                        if (verbose)
-                            errWriter.println(file);
-                        fileCount.incrementAndGet();
-                        NPETester p = new NPETester();
-                        p.test(read(file));
-                    } catch (AttributionException e) {
-                        if (!quiet) {
-                            error("Error attributing " + file + "\n" + e.getMessage());
+                        if (f.get(t) == null) {
+                            return f;
                         }
-                    } catch (IOException e) {
-                        error("Error reading " + file + ": " + e);
+                    }
+                    catch (IllegalAccessException e) {
+                        System.err.println("Cannot read field: " + f);
+                        //swallow it
                     }
                 }
-            });
-            return;
+                return null;
+            }
+
+            @Override
+            public void visitImport(JCImport tree) { }
+
+            @Override
+            public void visitTopLevel(JCCompilationUnit tree) {
+                scan(tree.defs);
+            }
+
+            JavaFileObject sourcefile;
+            EndPosTable endPosTable;
+            Info encl;
         }
-
-        if (!quiet)
-            error("File " + file + " ignored");
     }
 
     // See CR:  6982992 Tests CheckAttributedTree.java, JavacTreeScannerTest.java, and SourceTreeeScannerTest.java timeout
     StringWriter sw = new StringWriter();
     PrintWriter pw = new PrintWriter(sw);
-    Reporter r = new Reporter(pw);
 
-    /**
-     * Read a file.
-     * @param file the file to be read
-     * @return the tree for the content of the file
-     * @throws IOException if any IO errors occur
-     * @throws AttributionException if any errors occur while analyzing the file
-     */
-    List<Pair<JCCompilationUnit, JCTree>> read(File file) throws IOException, AttributionException {
-        r.errors = 0;
-        Iterable<? extends JavaFileObject> files = fm.get().getJavaFileObjects(file);
-        String[] opts = { "-XDshouldStopPolicy=ATTR", "-XDverboseCompilePolicy" };
-        JavacTask task = (JavacTask)comp.getTask(pw, fm.get(), r, Arrays.asList(opts), null, files);
-        final List<Element> analyzedElems = new ArrayList<>();
-        task.setTaskListener(new TaskListener() {
-            public void started(TaskEvent e) {
-                if (e.getKind() == TaskEvent.Kind.ANALYZE)
-                    analyzedElems.add(e.getTypeElement());
-            }
-            public void finished(TaskEvent e) { }
-        });
-        int i = 0;
-        try {
-            Iterable<? extends CompilationUnitTree> trees = task.parse();
-//            JavaCompiler c = JavaCompiler.instance(((JavacTaskImpl) task).getContext());
-//            System.err.println("verboseCompilePolicy: " + c.verboseCompilePolicy);
-//            System.err.println("shouldStopIfError: " + c.shouldStopPolicyIfError);
-//            System.err.println("shouldStopIfNoError: " + c.shouldStopPolicyIfNoError);
-            Iterable<? extends Element> elems = task.analyze();
-            if (!elems.iterator().hasNext())
-                throw new AttributionException("No results from analyze");
-            List<Pair<JCCompilationUnit, JCTree>> res = new ArrayList<>();
-            //System.err.println("Try to add pairs. Elems are " + analyzedElems);
-            for (CompilationUnitTree t : trees) {
-               JCCompilationUnit cu = (JCCompilationUnit)t;
-               for (JCTree def : cu.defs) {
-                   if (def.hasTag(CLASSDEF) &&
-                           analyzedElems.contains(((JCTree.JCClassDecl)def).sym)) {
-                       //System.err.println("Adding pair..." + cu.sourcefile + " " + ((JCTree.JCClassDecl) def).name);
-                       res.add((i++ % 2) == 0 ? new Pair<>(cu, def) {} : new Pair<>(cu, def));
-                   }
-               }
-            }
-            return res;
-        }
-        catch (Throwable t) {
-            throw new AttributionException("Exception while attributing file: " + file);
-        }
-    }
-
-    /**
-     * Report an error. When the program is complete, the program will either
-     * exit or throw an Error if any errors have been reported.
-     * @param msg the error message
-     */
-    void error(String msg) {
-        System.err.println();
-        System.err.println(msg);
-        System.err.println();
-        errCount.incrementAndGet();
-    }
+    StringWriter errSWriter = new StringWriter();
+    PrintWriter errWriter = new PrintWriter(errSWriter);
 
     /** Flag: don't report irrelevant files. */
     boolean quiet;
@@ -356,101 +476,6 @@
     TreeUtil treeUtil = new TreeUtil();
 
     /**
-     * Main class for testing assertions concerning types/symbol
-     * left uninitialized after attribution
-     */
-    private class NPETester extends TreeScanner {
-        void test(List<Pair<JCCompilationUnit, JCTree>> trees) {
-            for (Pair<JCCompilationUnit, JCTree> p : trees) {
-//              System.err.println("checking " + p.fst.sourcefile);
-                sourcefile = p.fst.sourcefile;
-                endPosTable = p.fst.endPositions;
-                encl = new Info(p.snd, endPosTable);
-                p.snd.accept(this);
-            }
-        }
-
-        @Override
-        public void scan(JCTree tree) {
-            if (tree == null ||
-                    excludeTags.contains(treeUtil.nameFromTag(tree.getTag()))) {
-                return;
-            }
-
-            Info self = new Info(tree, endPosTable);
-            if (mandatoryType(tree)) {
-                check(tree.type != null,
-                        "'null' field 'type' found in tree ", self);
-                if (tree.type==null)
-                    Thread.dumpStack();
-            }
-
-            Field errField = checkFields(tree);
-            if (errField!=null) {
-                check(false,
-                        "'null' field '" + errField.getName() + "' found in tree ", self);
-            }
-
-            Info prevEncl = encl;
-            encl = self;
-            tree.accept(this);
-            encl = prevEncl;
-        }
-
-        private boolean mandatoryType(JCTree that) {
-            return that instanceof JCTree.JCExpression ||
-                    that.hasTag(VARDEF) ||
-                    that.hasTag(METHODDEF) ||
-                    that.hasTag(CLASSDEF);
-        }
-
-        private final List<String> excludedFields = Arrays.asList("varargsElement", "targetType");
-
-        void check(boolean ok, String label, Info self) {
-            if (!ok) {
-                if (gui) {
-                    if (viewer == null)
-                        viewer = new Viewer();
-                    viewer.addEntry(sourcefile, label, encl, self);
-                }
-                error(label + self.toString() + " encl: " + encl.toString() +
-                        " in file: " + sourcefile + "  " + self.tree);
-            }
-        }
-
-        Field checkFields(JCTree t) {
-            List<Field> fieldsToCheck = treeUtil.getFieldsOfType(t,
-                    excludedFields,
-                    Symbol.class,
-                    Type.class);
-            for (Field f : fieldsToCheck) {
-                try {
-                    if (f.get(t) == null) {
-                        return f;
-                    }
-                }
-                catch (IllegalAccessException e) {
-                    System.err.println("Cannot read field: " + f);
-                    //swallow it
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public void visitImport(JCImport tree) { }
-
-        @Override
-        public void visitTopLevel(JCCompilationUnit tree) {
-            scan(tree.defs);
-        }
-
-        JavaFileObject sourcefile;
-        EndPosTable endPosTable;
-        Info encl;
-    }
-
-    /**
      * Utility class providing easy access to position and other info for a tree node.
      */
     private class Info {
@@ -524,25 +549,6 @@
     }
 
     /**
-     * DiagnosticListener to report diagnostics and count any errors that occur.
-     */
-    private static class Reporter implements DiagnosticListener<JavaFileObject> {
-        Reporter(PrintWriter out) {
-            this.out = out;
-        }
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            //out.println(diagnostic);
-            switch (diagnostic.getKind()) {
-                case ERROR:
-                    errors++;
-            }
-        }
-        int errors;
-        PrintWriter out;
-    }
-
-    /**
      * GUI viewer for issues found by TreePosTester. The viewer provides a drop
      * down list for selecting error conditions, a header area providing details
      * about an error, and a text area with the ranges of text highlighted as
--- a/langtools/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,30 +23,32 @@
 
 /*
  * @test
- * @bug 7046778 8006694
+ * @bug 7046778 8006694 8129962
  * @summary Project Coin: problem with diamond and member inner classes
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm DiamondAndInnerClassTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @compile -Xlint:all DiamondAndInnerClassTest.java
+ * @run main DiamondAndInnerClassTest
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import com.sun.source.util.JavacTask;
-import java.net.URI;
+import java.io.IOException;
 import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
 
-public class DiamondAndInnerClassTest
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+import combo.ComboTestHelper;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
 
-    enum TypeArgumentKind {
+public class DiamondAndInnerClassTest extends ComboInstance<DiamondAndInnerClassTest> {
+
+    enum TypeArgumentKind implements ComboParameter {
         NONE(""),
         STRING("<String>"),
         INTEGER("<Integer>"),
@@ -54,7 +56,7 @@
 
         String typeargStr;
 
-        private TypeArgumentKind(String typeargStr) {
+        TypeArgumentKind(String typeargStr) {
             this.typeargStr = typeargStr;
         }
 
@@ -75,252 +77,173 @@
                 default: throw new AssertionError("Unexpected decl kind: " + this);
             }
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return typeargStr;
+        }
     }
 
-    enum ArgumentKind {
+    enum ArgumentKind implements ComboParameter {
         OBJECT("(Object)null"),
         STRING("(String)null"),
         INTEGER("(Integer)null");
 
         String argStr;
 
-        private ArgumentKind(String argStr) {
+        ArgumentKind(String argStr) {
             this.argStr = argStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return argStr;
+        }
     }
 
-    enum TypeQualifierArity {
-        ONE(1, "A1#TA1"),
-        TWO(2, "A1#TA1.A2#TA2"),
-        THREE(3, "A1#TA1.A2#TA2.A3#TA3");
+    enum TypeQualifierArity implements ComboParameter {
+        ONE(1, "A1#{TA#IDX[0]}"),
+        TWO(2, "A1#{TA#IDX[0]}.A2#{TA#IDX[1]}"),
+        THREE(3, "A1#{TA#IDX[0]}.A2#{TA#IDX[1]}.A3#{TA#IDX[2]}");
 
         int n;
         String qualifierStr;
 
-        private TypeQualifierArity(int n, String qualifierStr) {
+        TypeQualifierArity(int n, String qualifierStr) {
             this.n = n;
             this.qualifierStr = qualifierStr;
         }
 
-        String getType(TypeArgumentKind... typeArgumentKinds) {
-            String res = qualifierStr;
-            for (int i = 1 ; i <= typeArgumentKinds.length ; i++) {
-                res = res.replace("#TA" + i, typeArgumentKinds[i-1].typeargStr);
-            }
-            return res;
-        }
-
-        boolean matches(InnerClassDeclArity innerClassDeclArity) {
-            return n ==innerClassDeclArity.n;
+        @Override
+        public String expand(String optParameter) {
+            return qualifierStr.replaceAll("#IDX", optParameter);
         }
     }
 
-    enum InnerClassDeclArity {
-        ONE(1, "class A1<X> { A1(X x1) { } #B }"),
-        TWO(2, "class A1<X1> { class A2<X2> { A2(X1 x1, X2 x2) { }  #B } }"),
-        THREE(3, "class A1<X1> { class A2<X2> { class A3<X3> { A3(X1 x1, X2 x2, X3 x3) { } #B } } }");
+    enum InnerClassDeclArity implements ComboParameter {
+        ONE(1, "class A1<X> { A1(X x1) { } #{BODY} }"),
+        TWO(2, "class A1<X1> { class A2<X2> { A2(X1 x1, X2 x2) { }  #{BODY} } }"),
+        THREE(3, "class A1<X1> { class A2<X2> { class A3<X3> { A3(X1 x1, X2 x2, X3 x3) { } #{BODY} } } }");
 
         int n;
         String classDeclStr;
 
-        private InnerClassDeclArity(int n, String classDeclStr) {
+        InnerClassDeclArity(int n, String classDeclStr) {
             this.n = n;
             this.classDeclStr = classDeclStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return classDeclStr;
+        }
     }
 
-    enum ArgumentListArity {
-        ONE(1, "(#A1)"),
-        TWO(2, "(#A1,#A2)"),
-        THREE(3, "(#A1,#A2,#A3)");
+    enum ArgumentListArity implements ComboParameter {
+        ONE(1, "(#{A[0]})"),
+        TWO(2, "(#{A[0]},#{A[1]})"),
+        THREE(3, "(#{A[0]},#{A[1]},#{A[2]})");
 
         int n;
         String argListStr;
 
-        private ArgumentListArity(int n, String argListStr) {
+        ArgumentListArity(int n, String argListStr) {
             this.n = n;
             this.argListStr = argListStr;
         }
 
-        String getArgs(ArgumentKind... argumentKinds) {
-            String res = argListStr;
-            for (int i = 1 ; i <= argumentKinds.length ; i++) {
-                res = res.replace("#A" + i, argumentKinds[i-1].argStr);
-            }
-            return res;
-        }
-
-        boolean matches(InnerClassDeclArity innerClassDeclArity) {
-            return n ==innerClassDeclArity.n;
+        @Override
+        public String expand(String optParameter) {
+            return argListStr.replaceAll("#IDX", optParameter);
         }
     }
 
     public static void main(String... args) throws Exception {
-        for (InnerClassDeclArity innerClassDeclArity : InnerClassDeclArity.values()) {
-            for (TypeQualifierArity declType : TypeQualifierArity.values()) {
-                if (!declType.matches(innerClassDeclArity)) continue;
-                for (TypeQualifierArity newClassType : TypeQualifierArity.values()) {
-                    if (!newClassType.matches(innerClassDeclArity)) continue;
-                    for (ArgumentListArity argList : ArgumentListArity.values()) {
-                        if (!argList.matches(innerClassDeclArity)) continue;
-                        for (TypeArgumentKind taDecl1 : TypeArgumentKind.values()) {
-                            boolean isDeclRaw = taDecl1 == TypeArgumentKind.NONE;
-                            //no diamond on decl site
-                            if (taDecl1 == TypeArgumentKind.DIAMOND) continue;
-                            for (TypeArgumentKind taSite1 : TypeArgumentKind.values()) {
-                                boolean isSiteRaw =
-                                        taSite1 == TypeArgumentKind.NONE;
-                                //diamond only allowed on the last type qualifier
-                                if (taSite1 == TypeArgumentKind.DIAMOND &&
-                                        innerClassDeclArity !=
-                                        InnerClassDeclArity.ONE)
-                                    continue;
-                                for (ArgumentKind arg1 : ArgumentKind.values()) {
-                                    if (innerClassDeclArity == innerClassDeclArity.ONE) {
-                                        pool.execute(
-                                                new DiamondAndInnerClassTest(
-                                                innerClassDeclArity, declType,
-                                                newClassType, argList,
-                                                new TypeArgumentKind[] {taDecl1},
-                                                new TypeArgumentKind[] {taSite1},
-                                                new ArgumentKind[] {arg1}));
-                                        continue;
-                                    }
-                                    for (TypeArgumentKind taDecl2 : TypeArgumentKind.values()) {
-                                        //no rare types
-                                        if (isDeclRaw != (taDecl2 == TypeArgumentKind.NONE))
-                                            continue;
-                                        //no diamond on decl site
-                                        if (taDecl2 == TypeArgumentKind.DIAMOND)
-                                            continue;
-                                        for (TypeArgumentKind taSite2 : TypeArgumentKind.values()) {
-                                            //no rare types
-                                            if (isSiteRaw != (taSite2 == TypeArgumentKind.NONE))
-                                                continue;
-                                            //diamond only allowed on the last type qualifier
-                                            if (taSite2 == TypeArgumentKind.DIAMOND &&
-                                                    innerClassDeclArity != InnerClassDeclArity.TWO)
-                                                continue;
-                                            for (ArgumentKind arg2 : ArgumentKind.values()) {
-                                                if (innerClassDeclArity == innerClassDeclArity.TWO) {
-                                                    pool.execute(
-                                                            new DiamondAndInnerClassTest(
-                                                            innerClassDeclArity,
-                                                            declType,
-                                                            newClassType,
-                                                            argList,
-                                                            new TypeArgumentKind[] {taDecl1, taDecl2},
-                                                            new TypeArgumentKind[] {taSite1, taSite2},
-                                                            new ArgumentKind[] {arg1, arg2}));
-                                                    continue;
-                                                }
-                                                for (TypeArgumentKind taDecl3 : TypeArgumentKind.values()) {
-                                                    //no rare types
-                                                    if (isDeclRaw != (taDecl3 == TypeArgumentKind.NONE))
-                                                        continue;
-                                                    //no diamond on decl site
-                                                    if (taDecl3 == TypeArgumentKind.DIAMOND)
-                                                        continue;
-                                                    for (TypeArgumentKind taSite3 : TypeArgumentKind.values()) {
-                                                        //no rare types
-                                                        if (isSiteRaw != (taSite3 == TypeArgumentKind.NONE))
-                                                            continue;
-                                                        //diamond only allowed on the last type qualifier
-                                                        if (taSite3 == TypeArgumentKind.DIAMOND &&
-                                                            innerClassDeclArity != InnerClassDeclArity.THREE)
-                                                            continue;
-                                                        for (ArgumentKind arg3 : ArgumentKind.values()) {
-                                                            if (innerClassDeclArity ==
-                                                                    innerClassDeclArity.THREE) {
-                                                                pool.execute(
-                                                                        new DiamondAndInnerClassTest(
-                                                                        innerClassDeclArity,
-                                                                        declType,
-                                                                        newClassType,
-                                                                        argList,
-                                                                        new TypeArgumentKind[] {taDecl1, taDecl2, taDecl3},
-                                                                        new TypeArgumentKind[] {taSite1, taSite2, taSite3},
-                                                                        new ArgumentKind[] {arg1, arg2, arg3}));
-                                                                continue;
-                                                            }
-                                                        }
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
+        new ComboTestHelper<DiamondAndInnerClassTest>()
+                .withFilter(DiamondAndInnerClassTest::rareTypesFilter)
+                .withFilter(DiamondAndInnerClassTest::noDiamondOnDecl)
+                .withFilter(DiamondAndInnerClassTest::noDiamondOnIntermediateTypes)
+                .withFilter(DiamondAndInnerClassTest::arityMismatch)
+                .withFilter(DiamondAndInnerClassTest::redundantFilter)
+                .withDimension("BODY", new ComboParameter.Constant<>("#{D.1} res = new #{S.2}#{AL};"))
+                .withDimension("DECL", (x, arity) -> x.innerClassDeclArity = arity, InnerClassDeclArity.values())
+                .withDimension("D", (x, arity) -> x.declArity = arity, TypeQualifierArity.values())
+                .withDimension("S", (x, arity) -> x.siteArity = arity, TypeQualifierArity.values())
+                .withDimension("AL", (x, alist) -> x.argumentListArity = alist, ArgumentListArity.values())
+                .withArrayDimension("TA1", (x, targs, idx) -> x.declTypeArgumentKinds[idx] = targs, 3, TypeArgumentKind.values())
+                .withArrayDimension("TA2", (x, targs, idx) -> x.siteTypeArgumentKinds[idx] = targs, 3, TypeArgumentKind.values())
+                .withArrayDimension("A", (x, argsk, idx) -> x.argumentKinds[idx] = argsk, 3, ArgumentKind.values())
+                .run(DiamondAndInnerClassTest::new);
+    }
+
+    InnerClassDeclArity innerClassDeclArity;
+    TypeQualifierArity declArity;
+    TypeQualifierArity siteArity;
+    TypeArgumentKind[] declTypeArgumentKinds = new TypeArgumentKind[3];
+    TypeArgumentKind[] siteTypeArgumentKinds = new TypeArgumentKind[3];
+    ArgumentKind[] argumentKinds = new ArgumentKind[3];
+    ArgumentListArity argumentListArity;
+
+    boolean rareTypesFilter() {
+        for (TypeArgumentKind[] types : Arrays.asList(declTypeArgumentKinds, siteTypeArgumentKinds)) {
+            boolean isRaw = types[0] == TypeArgumentKind.NONE;
+            for (int i = 1; i < innerClassDeclArity.n; i++) {
+                if (isRaw != (types[i] == TypeArgumentKind.NONE)) {
+                    return false;
                 }
             }
         }
+        return true;
+    }
 
-        checkAfterExec();
+    boolean noDiamondOnDecl() {
+        for (int i = 0; i < innerClassDeclArity.n; i++) {
+            if (declTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    boolean noDiamondOnIntermediateTypes() {
+        for (int i = 0; i < (innerClassDeclArity.n - 1); i++) {
+            if (siteTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND) {
+                return false;
+            }
+        }
+        return true;
     }
 
-    InnerClassDeclArity innerClassDeclArity;
-    TypeQualifierArity declType;
-    TypeQualifierArity siteType;
-    ArgumentListArity argList;
-    TypeArgumentKind[] declTypeArgumentKinds;
-    TypeArgumentKind[] siteTypeArgumentKinds;
-    ArgumentKind[] argumentKinds;
-    JavaSource source;
-    DiagnosticChecker diagChecker;
-
-    DiamondAndInnerClassTest(InnerClassDeclArity innerClassDeclArity,
-            TypeQualifierArity declType, TypeQualifierArity siteType,
-            ArgumentListArity argList, TypeArgumentKind[] declTypeArgumentKinds,
-            TypeArgumentKind[] siteTypeArgumentKinds, ArgumentKind[] argumentKinds) {
-        this.innerClassDeclArity = innerClassDeclArity;
-        this.declType = declType;
-        this.siteType = siteType;
-        this.argList = argList;
-        this.declTypeArgumentKinds = declTypeArgumentKinds;
-        this.siteTypeArgumentKinds = siteTypeArgumentKinds;
-        this.argumentKinds = argumentKinds;
-        this.source = new JavaSource();
-        this.diagChecker = new DiagnosticChecker();
+    boolean redundantFilter() {
+        for (TypeArgumentKind[] types : Arrays.asList(declTypeArgumentKinds, siteTypeArgumentKinds)) {
+            for (int i = innerClassDeclArity.n; i < types.length; i++) {
+                if (types[i].ordinal() != 0) {
+                    return false;
+                }
+            }
+        }
+        for (int i = innerClassDeclArity.n; i < argumentKinds.length; i++) {
+            if (argumentKinds[i].ordinal() != 0) {
+                return false;
+            }
+        }
+        return true;
     }
 
-    class JavaSource extends SimpleJavaFileObject {
-
-        String bodyTemplate = "#D res = new #S#AL;";
-
-        String source;
-
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = innerClassDeclArity.classDeclStr.replace("#B", bodyTemplate)
-                    .replace("#D", declType.getType(declTypeArgumentKinds))
-                    .replace("#S", siteType.getType(siteTypeArgumentKinds))
-                    .replace("#AL", argList.getArgs(argumentKinds));
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
+    boolean arityMismatch() {
+        return argumentListArity.n == innerClassDeclArity.n &&
+                siteArity.n == innerClassDeclArity.n &&
+                declArity.n == innerClassDeclArity.n;
     }
 
     @Override
-    public void run() {
-        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
-                null, null, Arrays.asList(source));
-        try {
-            ct.analyze();
-        } catch (Throwable ex) {
-            throw new AssertionError("Error thrown when compiling the following code:\n" +
-                    source.getCharContent(true));
-        }
-        check();
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withSourceFromTemplate("#{DECL}")
+                .analyze());
     }
 
-    void check() {
-        checkCount.incrementAndGet();
-
+    void check(Result<?> res) {
         boolean errorExpected = false;
 
         TypeArgumentKind[] expectedArgKinds =
@@ -345,24 +268,11 @@
             }
         }
 
-        if (errorExpected != diagChecker.errorFound) {
-            throw new Error("invalid diagnostics for source:\n" +
-                source.getCharContent(true) +
-                "\nFound error: " + diagChecker.errorFound +
+        if (errorExpected != res.hasErrors()) {
+            fail("invalid diagnostics for source:\n" +
+                res.compilationInfo() +
+                "\nFound error: " + res.hasErrors() +
                 "\nExpected error: " + errorExpected);
         }
     }
-
-    static class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean errorFound;
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errorFound = true;
-            }
-        }
-    }
-
 }
--- a/langtools/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,29 +23,29 @@
 
 /*
  * @test
- * @bug 7062745 8006694
+ * @bug 7062745 8006694 8129962
  * @summary  Regression: difference in overload resolution when two methods
  *  are maximally specific
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm GenericOverrideTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main GenericOverrideTest
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
 
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-public class GenericOverrideTest
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+public class GenericOverrideTest extends ComboInstance<GenericOverrideTest> {
 
     enum SourceLevel {
         SOURCE_7("-source", "7"),
@@ -58,24 +58,29 @@
         }
     }
 
-    enum SignatureKind {
+    enum SignatureKind implements ComboParameter {
         NON_GENERIC(""),
         GENERIC("<X>");
 
         String paramStr;
 
-        private SignatureKind(String paramStr) {
+        SignatureKind(String paramStr) {
             this.paramStr = paramStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return paramStr;
+        }
     }
 
-    enum ReturnTypeKind {
+    enum ReturnTypeKind implements ComboParameter {
         LIST("List"),
         ARRAYLIST("ArrayList");
 
         String retStr;
 
-        private ReturnTypeKind(String retStr) {
+        ReturnTypeKind(String retStr) {
             this.retStr = retStr;
         }
 
@@ -88,9 +93,14 @@
                 default: throw new AssertionError("Unexpected ret kind: " + this);
             }
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return retStr;
+        }
     }
 
-    enum TypeArgumentKind {
+    enum TypeArgumentKind implements ComboParameter {
         NONE(""),
         UNBOUND("<?>"),
         INTEGER("<Number>"),
@@ -99,7 +109,7 @@
 
         String typeargStr;
 
-        private TypeArgumentKind(String typeargStr) {
+        TypeArgumentKind(String typeargStr) {
             this.typeargStr = typeargStr;
         }
 
@@ -141,136 +151,79 @@
                 default: throw new AssertionError("Unexpected typearg kind: " + this);
             }
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return typeargStr;
+        }
     }
 
     public static void main(String... args) throws Exception {
-        for (SignatureKind sig1 : SignatureKind.values()) {
-            for (ReturnTypeKind rt1 : ReturnTypeKind.values()) {
-                for (TypeArgumentKind ta1 : TypeArgumentKind.values()) {
-                    if (!ta1.compatibleWith(sig1)) continue;
-                    for (SignatureKind sig2 : SignatureKind.values()) {
-                        for (ReturnTypeKind rt2 : ReturnTypeKind.values()) {
-                            for (TypeArgumentKind ta2 : TypeArgumentKind.values()) {
-                                if (!ta2.compatibleWith(sig2)) continue;
-                                for (ReturnTypeKind rt3 : ReturnTypeKind.values()) {
-                                    for (TypeArgumentKind ta3 : TypeArgumentKind.values()) {
-                                        if (!ta3.compatibleWith(SignatureKind.NON_GENERIC))
-                                            continue;
-                                        for (SourceLevel level : SourceLevel.values()) {
-                                            pool.execute(
-                                                    new GenericOverrideTest(sig1,
-                                                    rt1, ta1, sig2, rt2,
-                                                    ta2, rt3, ta3, level));
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec();
+        new ComboTestHelper<GenericOverrideTest>()
+                .withFilter(GenericOverrideTest::argMismatchFilter)
+                .withDimension("SOURCE", (x, level) -> x.level = level, SourceLevel.values())
+                .withArrayDimension("SIG", (x, sig, idx) -> x.sigs[idx] = sig, 2, SignatureKind.values())
+                .withArrayDimension("TARG", (x, targ, idx) -> x.targs[idx] = targ, 3, TypeArgumentKind.values())
+                .withArrayDimension("RET", (x, ret, idx) -> x.rets[idx] = ret, 3, ReturnTypeKind.values())
+                .run(GenericOverrideTest::new);
     }
 
-    SignatureKind sig1, sig2;
-    ReturnTypeKind rt1, rt2, rt3;
-    TypeArgumentKind ta1, ta2, ta3;
+    SignatureKind[] sigs = new SignatureKind[2];
+    ReturnTypeKind[] rets = new ReturnTypeKind[3];
+    TypeArgumentKind[] targs = new TypeArgumentKind[3];
     SourceLevel level;
-    JavaSource source;
-    DiagnosticChecker diagChecker;
 
-    GenericOverrideTest(SignatureKind sig1, ReturnTypeKind rt1, TypeArgumentKind ta1,
-            SignatureKind sig2, ReturnTypeKind rt2, TypeArgumentKind ta2,
-            ReturnTypeKind rt3, TypeArgumentKind ta3, SourceLevel level) {
-        this.sig1 = sig1;
-        this.sig2 = sig2;
-        this.rt1 = rt1;
-        this.rt2 = rt2;
-        this.rt3 = rt3;
-        this.ta1 = ta1;
-        this.ta2 = ta2;
-        this.ta3 = ta3;
-        this.level = level;
-        this.source = new JavaSource();
-        this.diagChecker = new DiagnosticChecker();
+    boolean argMismatchFilter() {
+        return targs[0].compatibleWith(sigs[0]) &&
+                targs[1].compatibleWith(sigs[1]) &&
+                targs[2].compatibleWith(SignatureKind.NON_GENERIC);
     }
 
-    class JavaSource extends SimpleJavaFileObject {
-
-        String template = "import java.util.*;\n" +
-                          "interface A { #S1 #R1#TA1 m(); }\n" +
-                          "interface B { #S2 #R2#TA2 m(); }\n" +
-                          "interface AB extends A, B {}\n" +
-                          "class Test {\n" +
-                          "  void test(AB ab) { #R3#TA3 n = ab.m(); }\n" +
-                          "}";
-
-        String source;
+    String template = "import java.util.*;\n" +
+                      "interface A { #{SIG[0]} #{RET[0]}#{TARG[0]} m(); }\n" +
+                      "interface B { #{SIG[1]} #{RET[1]}#{TARG[1]} m(); }\n" +
+                      "interface AB extends A, B {}\n" +
+                      "class Test {\n" +
+                      "  void test(AB ab) { #{RET[2]}#{TARG[2]} n = ab.m(); }\n" +
+                      "}";
 
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = template.replace("#S1", sig1.paramStr).
-                    replace("#S2", sig2.paramStr).
-                    replace("#R1", rt1.retStr).
-                    replace("#R2", rt2.retStr).
-                    replace("#R3", rt3.retStr).
-                    replace("#TA1", ta1.typeargStr).
-                    replace("#TA2", ta2.typeargStr).
-                    replace("#TA3", ta3.typeargStr);
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
+    @Override
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withOption("-XDuseUnsharedTable") //this test relies on predictable name indexes!
+                .withOptions(level.opts)
+                .withSourceFromTemplate(template)
+                .analyze());
     }
 
-    @Override
-    public void run() {
-        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
-                level.opts != null ? Arrays.asList(level.opts) : null,
-                null, Arrays.asList(source));
-        try {
-            ct.analyze();
-        } catch (Throwable ex) {
-            throw new AssertionError("Error thrown when compiling the following code:\n" +
-                    source.getCharContent(true));
-        }
-        check();
-    }
-
-    void check() {
-        checkCount.incrementAndGet();
-
+    void check(Result<?> res) {
         boolean errorExpected = false;
         int mostSpecific = 0;
 
         //first check that either |R1| <: |R2| or |R2| <: |R1|
-        if (rt1 != rt2) {
-            if (!rt1.moreSpecificThan(rt2) &&
-                    !rt2.moreSpecificThan(rt1)) {
+        if (rets[0] != rets[1]) {
+            if (!rets[0].moreSpecificThan(rets[1]) &&
+                    !rets[1].moreSpecificThan(rets[0])) {
                 errorExpected = true;
             } else {
-                mostSpecific = rt1.moreSpecificThan(rt2) ? 1 : 2;
+                mostSpecific = rets[0].moreSpecificThan(rets[1]) ? 1 : 2;
             }
         }
 
         //check that either TA1 <= TA2 or TA2 <= TA1 (unless most specific return found above is raw)
         if (!errorExpected) {
-            if (ta1 != ta2) {
-                boolean useStrictCheck = ta1.moreSpecificThan(ta2, true) ||
-                        ta2.moreSpecificThan(ta1, true);
-                if (!ta1.moreSpecificThan(ta2, useStrictCheck) &&
-                        !ta2.moreSpecificThan(ta1, useStrictCheck)) {
+            if (targs[0] != targs[1]) {
+                boolean useStrictCheck = targs[0].moreSpecificThan(targs[1], true) ||
+                        targs[1].moreSpecificThan(targs[0], true);
+                if (!targs[0].moreSpecificThan(targs[1], useStrictCheck) &&
+                        !targs[1].moreSpecificThan(targs[0], useStrictCheck)) {
                     errorExpected = true;
                 } else {
-                    int mostSpecific2 = ta1.moreSpecificThan(ta2, useStrictCheck) ? 1 : 2;
+                    int mostSpecific2 = targs[0].moreSpecificThan(targs[1], useStrictCheck) ? 1 : 2;
                     if (mostSpecific != 0 && mostSpecific2 != mostSpecific) {
                         errorExpected = mostSpecific == 1 ?
-                                ta1 != TypeArgumentKind.NONE :
-                                ta2 != TypeArgumentKind.NONE;
+                                targs[0] != TypeArgumentKind.NONE :
+                                targs[1] != TypeArgumentKind.NONE;
                     } else {
                         mostSpecific = mostSpecific2;
                     }
@@ -284,34 +237,21 @@
 
         //finally, check that most specific return type is compatible with expected type
         if (!errorExpected) {
-            ReturnTypeKind msrt = mostSpecific == 1 ? rt1 : rt2;
-            TypeArgumentKind msta = mostSpecific == 1 ? ta1 : ta2;
-            SignatureKind mssig = mostSpecific == 1 ? sig1 : sig2;
+            ReturnTypeKind msrt = mostSpecific == 1 ? rets[0] : rets[1];
+            TypeArgumentKind msta = mostSpecific == 1 ? targs[0] : targs[1];
+            SignatureKind mssig = mostSpecific == 1 ? sigs[0] : sigs[1];
 
-            if (!msrt.moreSpecificThan(rt3) ||
-                    !msta.assignableTo(ta3, mssig, level)) {
+            if (!msrt.moreSpecificThan(rets[2]) ||
+                    !msta.assignableTo(targs[2], mssig, level)) {
                 errorExpected = true;
             }
         }
 
-        if (errorExpected != diagChecker.errorFound) {
-            throw new Error("invalid diagnostics for source:\n" +
-                source.getCharContent(true) +
-                "\nFound error: " + diagChecker.errorFound +
+        if (errorExpected != res.hasErrors()) {
+            fail("invalid diagnostics for source:\n" +
+                res.compilationInfo() +
+                "\nFound error: " + res.hasErrors() +
                 "\nExpected error: " + errorExpected);
         }
     }
-
-    static class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean errorFound;
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errorFound = true;
-            }
-        }
-    }
-
 }
--- a/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,35 +23,32 @@
 
 /**
  * @test
- * @bug 8003280 8004102 8006694
+ * @bug 8003280 8004102 8006694 8129962
  * @summary Add lambda tests
  *  perform several automated checks in lambda conversion, esp. around accessibility
  *  temporarily workaround combo tests are causing time out in several platforms
- * @author  Maurizio Cimadamore
- * @library ../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/timeout=600/othervm FunctionalInterfaceConversionTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main FunctionalInterfaceConversionTest
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
 import java.io.IOException;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-import com.sun.source.util.JavacTask;
 
-public class FunctionalInterfaceConversionTest
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-    enum PackageKind {
+
+public class FunctionalInterfaceConversionTest extends ComboInstance<FunctionalInterfaceConversionTest> {
+
+    enum PackageKind implements ComboParameter {
         NO_PKG(""),
         PKG_A("a");
 
@@ -61,7 +58,8 @@
             this.pkg = pkg;
         }
 
-        String getPkgDecl() {
+        @Override
+        public String expand(String optParameter) {
             return this == NO_PKG ?
                 "" :
                 "package " + pkg + ";";
@@ -74,12 +72,12 @@
         }
     }
 
-    enum SamKind {
+    enum SamKind implements ComboParameter {
         CLASS("public class Sam {  }"),
         ABSTACT_CLASS("public abstract class Sam {  }"),
         ANNOTATION("public @interface Sam {  }"),
         ENUM("public enum Sam { }"),
-        INTERFACE("public interface Sam { \n #METH; \n }");
+        INTERFACE("public interface Sam { \n #{METH1}; \n }");
 
         String sam_str;
 
@@ -87,12 +85,13 @@
             this.sam_str = sam_str;
         }
 
-        String getSam(String methStr) {
-            return sam_str.replaceAll("#METH", methStr);
+        @Override
+        public String expand(String optParameter) {
+            return sam_str;
         }
     }
 
-    enum ModifierKind {
+    enum ModifierKind implements ComboParameter {
         PUBLIC("public"),
         PACKAGE("");
 
@@ -102,77 +101,73 @@
             this.modifier_str = modifier_str;
         }
 
-        boolean stricterThan(ModifierKind that) {
-            return this.ordinal() > that.ordinal();
+        @Override
+        public String expand(String optParameter) {
+            return modifier_str;
         }
     }
 
-    enum TypeKind {
+    enum TypeKind implements ComboParameter {
         EXCEPTION("Exception"),
         PKG_CLASS("PackageClass");
 
         String typeStr;
 
-        private TypeKind(String typeStr) {
+        TypeKind(String typeStr) {
             this.typeStr = typeStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return typeStr;
+        }
     }
 
-    enum ExprKind {
+    enum ExprKind implements ComboParameter {
         LAMBDA("x -> null"),
         MREF("this::m");
 
         String exprStr;
 
-        private ExprKind(String exprStr) {
+        ExprKind(String exprStr) {
             this.exprStr = exprStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return exprStr;
+        }
     }
 
-    enum MethodKind {
+    enum MethodKind implements ComboParameter {
         NONE(""),
-        NON_GENERIC("public abstract #R m(#ARG s) throws #T;"),
-        GENERIC("public abstract <X> #R m(#ARG s) throws #T;");
+        NON_GENERIC("public abstract #{RET} m(#{ARG} s) throws #{THROWN};"),
+        GENERIC("public abstract <X> #{RET} m(#{ARG} s) throws #{THROWN};");
 
         String methodTemplate;
 
-        private MethodKind(String methodTemplate) {
+        MethodKind(String methodTemplate) {
             this.methodTemplate = methodTemplate;
         }
 
-        String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) {
-            return methodTemplate.replaceAll("#R", retType.typeStr).
-                    replaceAll("#ARG", argType.typeStr).
-                    replaceAll("#T", thrownType.typeStr);
+        @Override
+        public String expand(String optParameter) {
+            return methodTemplate;
         }
     }
 
     public static void main(String[] args) throws Exception {
-        for (PackageKind samPkg : PackageKind.values()) {
-            for (ModifierKind modKind : ModifierKind.values()) {
-                for (SamKind samKind : SamKind.values()) {
-                    for (MethodKind samMeth : MethodKind.values()) {
-                        for (MethodKind clientMeth : MethodKind.values()) {
-                            for (TypeKind retType : TypeKind.values()) {
-                                for (TypeKind argType : TypeKind.values()) {
-                                    for (TypeKind thrownType : TypeKind.values()) {
-                                        for (ExprKind exprKind : ExprKind.values()) {
-                                            pool.execute(
-                                                new FunctionalInterfaceConversionTest(
-                                                    samPkg, modKind, samKind,
-                                                    samMeth, clientMeth, retType,
-                                                    argType, thrownType, exprKind));
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec(false);
+        new ComboTestHelper<FunctionalInterfaceConversionTest>()
+                .withDimension("PKG", (x, pkg) -> x.samPkg = pkg, PackageKind.values())
+                .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values())
+                .withDimension("CLAZZ", (x, sam) -> x.samKind = sam, SamKind.values())
+                .withDimension("METH1", (x, meth) -> x.samMeth = meth, MethodKind.values())
+                .withDimension("METH2", (x, meth) -> x.clientMeth = meth, MethodKind.values())
+                .withDimension("RET", (x, ret) -> x.retType = ret, TypeKind.values())
+                .withDimension("ARG", (x, arg) -> x.argType = arg, TypeKind.values())
+                .withDimension("THROWN", (x, thrown) -> x.thrownType = thrown, TypeKind.values())
+                .withDimension("EXPR", (x, expr) -> x.exprKind = expr, ExprKind.values())
+                .run(FunctionalInterfaceConversionTest::new);
     }
 
     PackageKind samPkg;
@@ -184,70 +179,32 @@
     TypeKind argType;
     TypeKind thrownType;
     ExprKind exprKind;
-    DiagnosticChecker dc;
 
-    SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") {
-        @Override
-        public String toString() {
-            return template.replaceAll("#P", samPkg.getPkgDecl()).
-                    replaceAll("#C", samKind.getSam(
-                    samMeth.getMethod(retType, argType, thrownType)));
-        }
-    };
-
-    SourceFile pkgClassSourceFile =
-            new SourceFile("PackageClass.java",
-                           "#P\n #M class PackageClass extends Exception { }") {
-        @Override
-        public String toString() {
-            return template.replaceAll("#P", samPkg.getPkgDecl()).
-                    replaceAll("#M", modKind.modifier_str);
-        }
-    };
+    String samSource = "#{PKG} \n #{CLAZZ}";
+    String pkgClassSource = "#{PKG}\n #{MOD} class PackageClass extends Exception { }";
+    String clientSource = "#{IMP}\n abstract class Client { \n" +
+                           "  Sam s = #{EXPR};\n" +
+                           "  #{METH2} \n }";
 
-    SourceFile clientSourceFile =
-            new SourceFile("Client.java",
-                           "#I\n abstract class Client { \n" +
-                           "  Sam s = #E;\n" +
-                           "  #M \n }") {
-        @Override
-        public String toString() {
-            return template.replaceAll("#I", samPkg.getImportStat())
-                    .replaceAll("#E", exprKind.exprStr)
-                    .replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType));
-        }
-    };
-
-    FunctionalInterfaceConversionTest(PackageKind samPkg, ModifierKind modKind,
-            SamKind samKind, MethodKind samMeth, MethodKind clientMeth,
-            TypeKind retType, TypeKind argType, TypeKind thrownType,
-            ExprKind exprKind) {
-        this.samPkg = samPkg;
-        this.modKind = modKind;
-        this.samKind = samKind;
-        this.samMeth = samMeth;
-        this.clientMeth = clientMeth;
-        this.retType = retType;
-        this.argType = argType;
-        this.thrownType = thrownType;
-        this.exprKind = exprKind;
-        this.dc = new DiagnosticChecker();
+    @Override
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withSourceFromTemplate("Sam", samSource)
+                .withSourceFromTemplate("PackageClass", pkgClassSource)
+                .withSourceFromTemplate("Client", clientSource, this::importStmt)
+                .analyze());
     }
 
-    @Override
-    public void run() {
-        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+    ComboParameter importStmt(String name) {
+        switch (name) {
+            case "IMP": return new ComboParameter.Constant<>(samPkg.getImportStat());
+            default: return null;
+        }
+    }
 
-        JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), dc, null, null,
-                Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile));
-        try {
-            ct.analyze();
-        } catch (IOException ex) {
-            throw new AssertionError("Test failing with cause", ex.getCause());
-        }
-        if (dc.errorFound == checkSamConversion()) {
-            throw new AssertionError(samSourceFile + "\n\n" +
-                pkgClassSourceFile + "\n\n" + clientSourceFile);
+    void check(Result<?> res) {
+        if (res.hasErrors() == checkSamConversion()) {
+            fail("Unexpected compilation result; " + res.compilationInfo());
         }
     }
 
@@ -276,35 +233,4 @@
             return true;
         }
     }
-
-    abstract class SourceFile extends SimpleJavaFileObject {
-
-        protected String template;
-
-        public SourceFile(String filename, String template) {
-            super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
-            this.template = template;
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return toString();
-        }
-
-        @Override
-        public abstract String toString();
-    }
-
-    static class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean errorFound = false;
-
-        @Override
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errorFound = true;
-            }
-        }
-    }
 }
--- a/langtools/test/tools/javac/lambda/LambdaParserTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/lambda/LambdaParserTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,39 +23,40 @@
 
 /*
  * @test
- * @bug 7115050 8003280 8005852 8006694
+ * @bug 7115050 8003280 8005852 8006694 8129962
  * @summary Add lambda tests
  *  Add parser support for lambda expressions
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm LambdaParserTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+
+ * @run main LambdaParserTest
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
 
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-public class LambdaParserTest
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+public class LambdaParserTest extends ComboInstance<LambdaParserTest> {
 
-    enum LambdaKind {
+    enum LambdaKind implements ComboParameter {
         NILARY_EXPR("()->x"),
         NILARY_STMT("()->{ return x; }"),
-        ONEARY_SHORT_EXPR("#PN->x"),
-        ONEARY_SHORT_STMT("#PN->{ return x; }"),
-        ONEARY_EXPR("(#M1 #T1 #PN)->x"),
-        ONEARY_STMT("(#M1 #T1 #PN)->{ return x; }"),
-        TWOARY_EXPR("(#M1 #T1 #PN, #M2 #T2 y)->x"),
-        TWOARY_STMT("(#M1 #T1 #PN, #M2 #T2 y)->{ return x; }");
+        ONEARY_SHORT_EXPR("#{NAME}->x"),
+        ONEARY_SHORT_STMT("#{NAME}->{ return x; }"),
+        ONEARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME})->x"),
+        ONEARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME})->{ return x; }"),
+        TWOARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->x"),
+        TWOARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->{ return x; }");
 
         String lambdaTemplate;
 
@@ -63,13 +64,9 @@
             this.lambdaTemplate = lambdaTemplate;
         }
 
-        String getLambdaString(LambdaParameterKind pk1, LambdaParameterKind pk2,
-                ModifierKind mk1, ModifierKind mk2, LambdaParameterName pn) {
-            return lambdaTemplate.replaceAll("#M1", mk1.modifier)
-                    .replaceAll("#M2", mk2.modifier)
-                    .replaceAll("#T1", pk1.parameterType)
-                    .replaceAll("#T2", pk2.parameterType)
-                    .replaceAll("#PN", pn.nameStr);
+        @Override
+        public String expand(String optParameter) {
+            return lambdaTemplate;
         }
 
         int arity() {
@@ -92,7 +89,7 @@
         }
     }
 
-    enum LambdaParameterName {
+    enum LambdaParameterName implements ComboParameter {
         IDENT("x"),
         UNDERSCORE("_");
 
@@ -101,9 +98,14 @@
         LambdaParameterName(String nameStr) {
             this.nameStr = nameStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return nameStr;
+        }
     }
 
-    enum LambdaParameterKind {
+    enum LambdaParameterKind implements ComboParameter {
         IMPLICIT(""),
         EXPLIICT_SIMPLE("A"),
         EXPLIICT_SIMPLE_ARR1("A[]"),
@@ -129,9 +131,14 @@
             return this == EXPLICIT_VARARGS ||
                     this == EXPLICIT_GENERIC2_VARARGS;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return parameterType;
+        }
     }
 
-    enum ModifierKind {
+    enum ModifierKind implements ComboParameter {
         NONE(""),
         FINAL("final"),
         PUBLIC("public");
@@ -150,15 +157,20 @@
                 default: throw new AssertionError("Invalid modifier kind " + this);
             }
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return modifier;
+        }
     }
 
-    enum ExprKind {
-        NONE("#L#S"),
-        SINGLE_PAREN1("(#L#S)"),
-        SINGLE_PAREN2("(#L)#S"),
-        DOUBLE_PAREN1("((#L#S))"),
-        DOUBLE_PAREN2("((#L)#S)"),
-        DOUBLE_PAREN3("((#L))#S");
+    enum ExprKind implements ComboParameter {
+        NONE("#{LAMBDA}#{SUBEXPR}"),
+        SINGLE_PAREN1("(#{LAMBDA}#{SUBEXPR})"),
+        SINGLE_PAREN2("(#{LAMBDA})#{SUBEXPR}"),
+        DOUBLE_PAREN1("((#{LAMBDA}#{SUBEXPR}))"),
+        DOUBLE_PAREN2("((#{LAMBDA})#{SUBEXPR})"),
+        DOUBLE_PAREN3("((#{LAMBDA}))#{SUBEXPR}");
 
         String expressionTemplate;
 
@@ -166,14 +178,13 @@
             this.expressionTemplate = expressionTemplate;
         }
 
-        String expressionString(LambdaParameterKind pk1, LambdaParameterKind pk2,
-                ModifierKind mk1, ModifierKind mk2, LambdaKind lk, LambdaParameterName pn, SubExprKind sk) {
-            return expressionTemplate.replaceAll("#L", lk.getLambdaString(pk1, pk2, mk1, mk2, pn))
-                    .replaceAll("#S", sk.subExpression);
+        @Override
+        public String expand(String optParameter) {
+            return expressionTemplate;
         }
     }
 
-    enum SubExprKind {
+    enum SubExprKind implements ComboParameter {
         NONE(""),
         SELECT_FIELD(".f"),
         SELECT_METHOD(".f()"),
@@ -186,133 +197,78 @@
         SubExprKind(String subExpression) {
             this.subExpression = subExpression;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return subExpression;
+        }
     }
 
     public static void main(String... args) throws Exception {
-        for (LambdaKind lk : LambdaKind.values()) {
-            for (LambdaParameterName pn : LambdaParameterName.values()) {
-                for (LambdaParameterKind pk1 : LambdaParameterKind.values()) {
-                    if (lk.arity() < 1 && pk1 != LambdaParameterKind.IMPLICIT)
-                        continue;
-                    for (LambdaParameterKind pk2 : LambdaParameterKind.values()) {
-                        if (lk.arity() < 2 && pk2 != LambdaParameterKind.IMPLICIT)
-                            continue;
-                        for (ModifierKind mk1 : ModifierKind.values()) {
-                            if (mk1 != ModifierKind.NONE && lk.isShort())
-                                continue;
-                            if (lk.arity() < 1 && mk1 != ModifierKind.NONE)
-                                continue;
-                            for (ModifierKind mk2 : ModifierKind.values()) {
-                                if (lk.arity() < 2 && mk2 != ModifierKind.NONE)
-                                    continue;
-                                for (SubExprKind sk : SubExprKind.values()) {
-                                    for (ExprKind ek : ExprKind.values()) {
-                                        pool.execute(
-                                            new LambdaParserTest(pk1, pk2, mk1,
-                                                                 mk2, lk, sk, ek, pn));
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec();
+        new ComboTestHelper<LambdaParserTest>()
+                .withFilter(LambdaParserTest::redundantTestFilter)
+                .withFilter(LambdaParserTest::badImplicitFilter)
+                .withDimension("LAMBDA", (x, lk) -> x.lk = lk, LambdaKind.values())
+                .withDimension("NAME", (x, name) -> x.pn = name, LambdaParameterName.values())
+                .withArrayDimension("TYPE", (x, type, idx) -> x.pks[idx] = type, 2, LambdaParameterKind.values())
+                .withArrayDimension("MOD", (x, mod, idx) -> x.mks[idx] = mod, 2, ModifierKind.values())
+                .withDimension("EXPR", ExprKind.values())
+                .withDimension("SUBEXPR", SubExprKind.values())
+                .run(LambdaParserTest::new);
     }
 
-    LambdaParameterKind pk1;
-    LambdaParameterKind pk2;
-    ModifierKind mk1;
-    ModifierKind mk2;
+    LambdaParameterKind[] pks = new LambdaParameterKind[2];
+    ModifierKind[] mks = new ModifierKind[2];
     LambdaKind lk;
     LambdaParameterName pn;
-    SubExprKind sk;
-    ExprKind ek;
-    JavaSource source;
-    DiagnosticChecker diagChecker;
+
+    boolean badImplicitFilter() {
+        return !(mks[0] != ModifierKind.NONE && lk.isShort());
+    }
 
-    LambdaParserTest(LambdaParameterKind pk1, LambdaParameterKind pk2,
-            ModifierKind mk1, ModifierKind mk2, LambdaKind lk,
-            SubExprKind sk, ExprKind ek, LambdaParameterName pn) {
-        this.pk1 = pk1;
-        this.pk2 = pk2;
-        this.mk1 = mk1;
-        this.mk2 = mk2;
-        this.lk = lk;
-        this.pn = pn;
-        this.sk = sk;
-        this.ek = ek;
-        this.source = new JavaSource();
-        this.diagChecker = new DiagnosticChecker();
+    boolean redundantTestFilter() {
+        for (int i = lk.arity(); i < mks.length ; i++) {
+            if (mks[i].ordinal() != 0) {
+                return false;
+            }
+        }
+        for (int i = lk.arity(); i < pks.length ; i++) {
+            if (pks[i].ordinal() != 0) {
+                return false;
+            }
+        }
+        return true;
     }
 
-    class JavaSource extends SimpleJavaFileObject {
-
-        String template = "class Test {\n" +
-                          "   SAM s = #E;\n" +
-                          "}";
-
-        String source;
+    String template = "class Test {\n" +
+                      "   SAM s = #{EXPR};\n" +
+                      "}";
 
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = template.replaceAll("#E",
-                    ek.expressionString(pk1, pk2, mk1, mk2, lk, pn, sk));
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
+    @Override
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withSourceFromTemplate(template)
+                .parse());
     }
 
-    public void run() {
-        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
-                null, null, Arrays.asList(source));
-        try {
-            ct.parse();
-        } catch (Throwable ex) {
-            processException(ex);
-            return;
-        }
-        check();
-    }
-
-    void check() {
-        checkCount.incrementAndGet();
-
-        boolean errorExpected = (lk.arity() > 0 && !mk1.compatibleWith(pk1)) ||
-                (lk.arity() > 1 && !mk2.compatibleWith(pk2));
+    void check(Result<?> res) {
+        boolean errorExpected = (lk.arity() > 0 && !mks[0].compatibleWith(pks[0])) ||
+                (lk.arity() > 1 && !mks[1].compatibleWith(pks[1]));
 
         if (lk.arity() == 2 &&
-                (pk1.explicit() != pk2.explicit() ||
-                pk1.isVarargs())) {
+                (pks[0].explicit() != pks[1].explicit() ||
+                pks[0].isVarargs())) {
             errorExpected = true;
         }
 
         errorExpected |= pn == LambdaParameterName.UNDERSCORE &&
                 lk.arity() > 0;
 
-        if (errorExpected != diagChecker.errorFound) {
-            throw new Error("invalid diagnostics for source:\n" +
-                source.getCharContent(true) +
-                "\nFound error: " + diagChecker.errorFound +
+        if (errorExpected != res.hasErrors()) {
+            fail("invalid diagnostics for source:\n" +
+                res.compilationInfo() +
+                "\nFound error: " + res.hasErrors() +
                 "\nExpected error: " + errorExpected);
         }
     }
-
-    static class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean errorFound;
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errorFound = true;
-            }
-        }
-    }
-
 }
--- a/langtools/test/tools/javac/lambda/MethodReferenceParserTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReferenceParserTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,39 +23,39 @@
 
 /*
  * @test
- * @bug 7115052 8003280 8006694
+ * @bug 7115052 8003280 8006694 8129962
  * @summary Add lambda tests
  *  Add parser support for method references
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm MethodReferenceParserTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main MethodReferenceParserTest
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
 
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
+
+public class MethodReferenceParserTest extends ComboInstance<MethodReferenceParserTest> {
 
-public class MethodReferenceParserTest
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
-
-    enum ReferenceKind {
-        METHOD_REF("#Q::#Gm"),
-        CONSTRUCTOR_REF("#Q::#Gnew"),
+    enum ReferenceKind implements ComboParameter {
+        METHOD_REF("#{QUAL}::#{TARGS}m"),
+        CONSTRUCTOR_REF("#{QUAL}::#{TARGS}new"),
         FALSE_REF("min < max"),
-        ERR_SUPER("#Q::#Gsuper"),
-        ERR_METH0("#Q::#Gm()"),
-        ERR_METH1("#Q::#Gm(X)"),
-        ERR_CONSTR0("#Q::#Gnew()"),
-        ERR_CONSTR1("#Q::#Gnew(X)");
+        ERR_SUPER("#{QUAL}::#{TARGS}super"),
+        ERR_METH0("#{QUAL}::#{TARGS}m()"),
+        ERR_METH1("#{QUAL}::#{TARGS}m(X)"),
+        ERR_CONSTR0("#{QUAL}::#{TARGS}new()"),
+        ERR_CONSTR1("#{QUAL}::#{TARGS}new(X)");
 
         String referenceTemplate;
 
@@ -63,12 +63,6 @@
             this.referenceTemplate = referenceTemplate;
         }
 
-        String getReferenceString(QualifierKind qk, GenericKind gk) {
-            return referenceTemplate
-                    .replaceAll("#Q", qk.qualifier)
-                    .replaceAll("#G", gk.typeParameters);
-        }
-
         boolean erroneous() {
             switch (this) {
                 case ERR_SUPER:
@@ -80,11 +74,16 @@
                 default: return false;
             }
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return referenceTemplate;
+        }
     }
 
-    enum ContextKind {
-        ASSIGN("SAM s = #E;"),
-        METHOD("m(#E, i);");
+    enum ContextKind implements ComboParameter {
+        ASSIGN("SAM s = #{EXPR};"),
+        METHOD("m(#{EXPR}, i);");
 
         String contextTemplate;
 
@@ -92,13 +91,13 @@
             this.contextTemplate = contextTemplate;
         }
 
-        String contextString(ExprKind ek, ReferenceKind rk, QualifierKind qk,
-                GenericKind gk, SubExprKind sk) {
-            return contextTemplate.replaceAll("#E", ek.expressionString(rk, qk, gk, sk));
+        @Override
+        public String expand(String optParameter) {
+            return contextTemplate;
         }
     }
 
-    enum GenericKind {
+    enum GenericKind implements ComboParameter {
         NONE(""),
         ONE("<X>"),
         TWO("<X,Y>");
@@ -108,9 +107,14 @@
         GenericKind(String typeParameters) {
             this.typeParameters = typeParameters;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return typeParameters;
+        }
     }
 
-    enum QualifierKind {
+    enum QualifierKind implements ComboParameter {
         THIS("this"),
         SUPER("super"),
         NEW("new Foo()"),
@@ -131,15 +135,20 @@
         QualifierKind(String qualifier) {
             this.qualifier = qualifier;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return qualifier;
+        }
     }
 
-    enum ExprKind {
-        NONE("#R::S"),
-        SINGLE_PAREN1("(#R#S)"),
-        SINGLE_PAREN2("(#R)#S"),
-        DOUBLE_PAREN1("((#R#S))"),
-        DOUBLE_PAREN2("((#R)#S)"),
-        DOUBLE_PAREN3("((#R))#S");
+    enum ExprKind implements ComboParameter {
+        NONE("#{MREF}"),
+        SINGLE_PAREN1("(#{MREF}#{SUBEXPR})"),
+        SINGLE_PAREN2("(#{MREF})#{SUBEXPR}"),
+        DOUBLE_PAREN1("((#{MREF}#{SUBEXPR}))"),
+        DOUBLE_PAREN2("((#{MREF})#{SUBEXPR})"),
+        DOUBLE_PAREN3("((#{MREF}))#{SUBEXPR}");
 
         String expressionTemplate;
 
@@ -147,14 +156,13 @@
             this.expressionTemplate = expressionTemplate;
         }
 
-        String expressionString(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk) {
-            return expressionTemplate
-                    .replaceAll("#R", rk.getReferenceString(qk, gk))
-                    .replaceAll("#S", sk.subExpression);
+        @Override
+        public String expand(String optParameter) {
+            return expressionTemplate;
         }
     }
 
-    enum SubExprKind {
+    enum SubExprKind implements ComboParameter {
         NONE(""),
         SELECT_FIELD(".f"),
         SELECT_METHOD(".f()"),
@@ -167,100 +175,45 @@
         SubExprKind(String subExpression) {
             this.subExpression = subExpression;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return subExpression;
+        }
     }
 
     public static void main(String... args) throws Exception {
-        for (ReferenceKind rk : ReferenceKind.values()) {
-            for (QualifierKind qk : QualifierKind.values()) {
-                for (GenericKind gk : GenericKind.values()) {
-                    for (SubExprKind sk : SubExprKind.values()) {
-                        for (ExprKind ek : ExprKind.values()) {
-                            for (ContextKind ck : ContextKind.values()) {
-                                pool.execute(new MethodReferenceParserTest(rk, qk, gk, sk, ek, ck));
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec();
+        new ComboTestHelper<MethodReferenceParserTest>()
+                .withDimension("MREF", (x, ref) -> x.rk = ref, ReferenceKind.values())
+                .withDimension("QUAL", QualifierKind.values())
+                .withDimension("TARGS", GenericKind.values())
+                .withDimension("EXPR", ExprKind.values())
+                .withDimension("SUBEXPR", SubExprKind.values())
+                .withDimension("CTX", ContextKind.values())
+                .run(MethodReferenceParserTest::new);
     }
 
     ReferenceKind rk;
-    QualifierKind qk;
-    GenericKind gk;
-    SubExprKind sk;
-    ExprKind ek;
-    ContextKind ck;
-    JavaSource source;
-    DiagnosticChecker diagChecker;
 
-    MethodReferenceParserTest(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk, ExprKind ek, ContextKind ck) {
-        this.rk = rk;
-        this.qk = qk;
-        this.gk = gk;
-        this.sk = sk;
-        this.ek = ek;
-        this.ck = ck;
-        this.source = new JavaSource();
-        this.diagChecker = new DiagnosticChecker();
+    String template = "class Test {\n" +
+                      "   void test() {\n" +
+                      "      #{CTX}\n" +
+                      "   }" +
+                      "}";
+
+    @Override
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withSourceFromTemplate(template)
+                .parse());
     }
 
-    class JavaSource extends SimpleJavaFileObject {
-
-        String template = "class Test {\n" +
-                          "   void test() {\n" +
-                          "      #C\n" +
-                          "   }" +
-                          "}";
-
-        String source;
-
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = template.replaceAll("#C", ck.contextString(ek, rk, qk, gk, sk));
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
-    }
-
-    @Override
-    public void run() {
-        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
-                null, null, Arrays.asList(source));
-        try {
-            ct.parse();
-        } catch (Throwable ex) {
-            processException(ex);
-            return;
-        }
-        check();
-    }
-
-    void check() {
-        checkCount.incrementAndGet();
-
-        if (diagChecker.errorFound != rk.erroneous()) {
-            throw new Error("invalid diagnostics for source:\n" +
-                source.getCharContent(true) +
-                "\nFound error: " + diagChecker.errorFound +
+    void check(Result<?> res) {
+        if (res.hasErrors() != rk.erroneous()) {
+            fail("invalid diagnostics for source:\n" +
+                res.compilationInfo() +
+                "\nFound error: " + res.hasErrors() +
                 "\nExpected error: " + rk.erroneous());
         }
     }
-
-    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean errorFound;
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errorFound = true;
-            }
-        }
-    }
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/TestBootstrapMethodsCount.java	Mon Aug 31 17:33:34 2015 +0100
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2012, 2015, 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.
+ */
+
+/*
+ * @test
+ * @bug 8129547
+ * @summary Excess entries in BootstrapMethods with the same (bsm, bsmKind, bsmStaticArgs), but different dynamicArgs
+ * @library /tools/javac/lib
+ * @modules jdk.jdeps/com.sun.tools.classfile
+ *          jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ */
+
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Locale;
+
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskListener;
+import com.sun.source.util.TreeScanner;
+
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.BootstrapMethods_attribute;
+import com.sun.tools.classfile.ClassFile;
+
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Names;
+
+import static com.sun.tools.javac.jvm.ClassFile.*;
+
+public class TestBootstrapMethodsCount {
+
+    public static void main(String... args) throws Exception {
+        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+        new TestBootstrapMethodsCount().run(comp);
+    }
+
+    DiagChecker dc;
+
+    TestBootstrapMethodsCount() {
+        dc = new DiagChecker();
+    }
+
+    public void run(JavaCompiler comp) {
+        JavaSource source = new JavaSource();
+        JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, null, dc,
+                Arrays.asList("-g"), null, Arrays.asList(source));
+        Context context = ct.getContext();
+        Symtab syms = Symtab.instance(context);
+        Names names = Names.instance(context);
+        Types types = Types.instance(context);
+        ct.addTaskListener(new Indifier(syms, names, types));
+        try {
+            ct.generate();
+        } catch (Throwable t) {
+            t.printStackTrace();
+            throw new AssertionError(
+                    String.format("Error thrown when compiling following code\n%s",
+                            source.source));
+        }
+        if (dc.diagFound) {
+            throw new AssertionError(
+                    String.format("Diags found when compiling following code\n%s\n\n%s",
+                            source.source, dc.printDiags()));
+        }
+        verifyBytecode();
+    }
+
+    void verifyBytecode() {
+        File compiledTest = new File("Test.class");
+        try {
+            ClassFile cf = ClassFile.read(compiledTest);
+            BootstrapMethods_attribute bsm_attr =
+                    (BootstrapMethods_attribute)cf
+                            .getAttribute(Attribute.BootstrapMethods);
+            int length = bsm_attr.bootstrap_method_specifiers.length;
+            if (length != 1) {
+                throw new Error("Bad number of method specifiers " +
+                        "in BootstrapMethods attribute: " + length);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new Error("error reading " + compiledTest +": " + e);
+        }
+    }
+
+    class JavaSource extends SimpleJavaFileObject {
+
+        static final String source = "import java.lang.invoke.*;\n" +
+                "class Bootstrap {\n" +
+                "   public static CallSite bsm(MethodHandles.Lookup lookup, " +
+                "String name, MethodType methodType) {\n" +
+                "       return null;\n" +
+                "   }\n" +
+                "}\n" +
+                "class Test {\n" +
+                "   void m1() { }\n" +
+                "   void m2(Object arg1) { }\n" +
+                "   void test1() {\n" +
+                "      Object o = this; // marker statement \n" +
+                "      m1();\n" +
+                "   }\n" +
+                "   void test2(Object arg1) {\n" +
+                "      Object o = this; // marker statement \n" +
+                "      m2(arg1);\n" +
+                "   }\n" +
+                "}";
+
+        JavaSource() {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+    }
+
+    class Indifier extends TreeScanner<Void, Void> implements TaskListener {
+
+        MethodSymbol bsm;
+        Symtab syms;
+        Names names;
+        Types types;
+
+        Indifier(Symtab syms, Names names, Types types) {
+            this.syms = syms;
+            this.names = names;
+            this.types = types;
+        }
+
+        @Override
+        public void started(TaskEvent e) {
+            //do nothing
+        }
+
+        @Override
+        public void finished(TaskEvent e) {
+            if (e.getKind() == TaskEvent.Kind.ANALYZE) {
+                scan(e.getCompilationUnit(), null);
+            }
+        }
+
+        @Override
+        public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
+            super.visitMethodInvocation(node, p);
+            JCMethodInvocation apply = (JCMethodInvocation)node;
+            JCIdent ident = (JCIdent)apply.meth;
+            Symbol oldSym = ident.sym;
+            if (!oldSym.isConstructor()) {
+                ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name,
+                        oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]);
+            }
+            return null;
+        }
+
+        @Override
+        public Void visitMethod(MethodTree node, Void p) {
+            super.visitMethod(node, p);
+            if (node.getName().toString().equals("bsm")) {
+                bsm = ((JCMethodDecl)node).sym;
+            }
+            return null;
+        }
+    }
+
+    static class DiagChecker
+            implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+        boolean diagFound;
+        ArrayList<String> diags = new ArrayList<>();
+
+        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+            diags.add(diagnostic.getMessage(Locale.getDefault()));
+            diagFound = true;
+        }
+
+        String printDiags() {
+            StringBuilder buf = new StringBuilder();
+            for (String s : diags) {
+                buf.append(s);
+                buf.append("\n");
+            }
+            return buf.toString();
+        }
+    }
+
+}
--- a/langtools/test/tools/javac/lambda/TestInvokeDynamic.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/lambda/TestInvokeDynamic.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,33 +23,27 @@
 
 /*
  * @test
- * @bug 7194586 8003280 8006694 8010404
+ * @bug 7194586 8003280 8006694 8010404 8129962
  * @summary Add lambda tests
  *  Add back-end support for invokedynamic
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../lib
+ * @library /tools/javac/lib
  * @modules jdk.jdeps/com.sun.tools.classfile
  *          jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
  *          jdk.compiler/com.sun.tools.javac.jvm
  *          jdk.compiler/com.sun.tools.javac.tree
  *          jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm TestInvokeDynamic
+ * @build combo.ComboTestHelper
+ * @run main TestInvokeDynamic
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
+import java.io.InputStream;
 
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Locale;
-
-import javax.tools.Diagnostic;
 import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
 
 import com.sun.source.tree.MethodInvocationTree;
 import com.sun.source.tree.MethodTree;
@@ -78,13 +72,17 @@
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.Names;
 
+import combo.ComboParameter;
+import combo.ComboTask;
+import combo.ComboTestHelper;
+import combo.ComboInstance;
+import combo.ComboTask.Result;
+
 import static com.sun.tools.javac.jvm.ClassFile.*;
 
-public class TestInvokeDynamic
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
 
-    enum StaticArgumentKind {
+    enum StaticArgumentKind implements ComboParameter {
         STRING("Hello!", "String", "Ljava/lang/String;") {
             @Override
             boolean check(CPInfo cpInfo) throws Exception {
@@ -189,88 +187,91 @@
                     throw new AssertionError();
             }
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return sourceTypeStr;
+        }
     }
 
-    enum StaticArgumentsArity {
-        ZERO(0),
-        ONE(1),
-        TWO(2),
-        THREE(3);
+    enum StaticArgumentsArity implements ComboParameter {
+        ZERO(0, ""),
+        ONE(1, ",#{SARG[0]} s1"),
+        TWO(2, ",#{SARG[0]} s1, #{SARG[1]} s2"),
+        THREE(3, ",#{SARG[0]} s1, #{SARG[1]} s2, #{SARG[2]} s3");
 
         int arity;
+        String argsTemplate;
 
-        StaticArgumentsArity(int arity) {
+        StaticArgumentsArity(int arity, String argsTemplate) {
             this.arity = arity;
+            this.argsTemplate = argsTemplate;
+        }
+
+        @Override
+        public String expand(String optParameter) {
+            return argsTemplate;
         }
     }
 
     public static void main(String... args) throws Exception {
-        for (StaticArgumentsArity arity : StaticArgumentsArity.values()) {
-            if (arity.arity == 0) {
-                pool.execute(new TestInvokeDynamic(arity));
-            } else {
-                for (StaticArgumentKind sak1 : StaticArgumentKind.values()) {
-                    if (arity.arity == 1) {
-                        pool.execute(new TestInvokeDynamic(arity, sak1));
-                    } else {
-                        for (StaticArgumentKind sak2 : StaticArgumentKind.values()) {
-                            if (arity.arity == 2) {
-                                pool.execute(new TestInvokeDynamic(arity, sak1, sak2));
-                            } else {
-                                for (StaticArgumentKind sak3 : StaticArgumentKind.values()) {
-                                    pool.execute(
-                                        new TestInvokeDynamic(arity, sak1, sak2, sak3));
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec();
+        new ComboTestHelper<TestInvokeDynamic>()
+                .withFilter(TestInvokeDynamic::redundantTestFilter)
+                .withDimension("SARGS", (x, arity) -> x.arity = arity, StaticArgumentsArity.values())
+                .withArrayDimension("SARG", (x, arg, idx) -> x.saks[idx] = arg, 3, StaticArgumentKind.values())
+                .run(TestInvokeDynamic::new);
     }
 
     StaticArgumentsArity arity;
-    StaticArgumentKind[] saks;
-    DiagChecker dc;
+    StaticArgumentKind[] saks = new StaticArgumentKind[3];
 
-    TestInvokeDynamic(StaticArgumentsArity arity, StaticArgumentKind... saks) {
-        this.arity = arity;
-        this.saks = saks;
-        dc = new DiagChecker();
+    boolean redundantTestFilter() {
+        for (int i = arity.arity ; i < saks.length ; i++) {
+            if (saks[i].ordinal() != 0) {
+                return false;
+            }
+        }
+        return true;
     }
 
-    public void run() {
-        int id = checkCount.incrementAndGet();
-        JavaSource source = new JavaSource(id);
-        JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc,
-                Arrays.asList("-g"), null, Arrays.asList(source));
+    final String source_template =
+                "import java.lang.invoke.*;\n" +
+                "class Test {\n" +
+                "   void m() { }\n" +
+                "   void test() {\n" +
+                "      Object o = this; // marker statement \n" +
+                "      m();\n" +
+                "   }\n" +
+                "}\n" +
+                "class Bootstrap {\n" +
+                "   public static CallSite bsm(MethodHandles.Lookup lookup, " +
+                "String name, MethodType methodType #{SARGS}) {\n" +
+                "       return null;\n" +
+                "   }\n" +
+                "}";
+
+    @Override
+    public void doWork() throws IOException {
+        ComboTask comboTask = newCompilationTask()
+                .withOption("-g")
+                .withSourceFromTemplate(source_template);
+
+        JavacTaskImpl ct = (JavacTaskImpl)comboTask.getTask();
         Context context = ct.getContext();
         Symtab syms = Symtab.instance(context);
         Names names = Names.instance(context);
         Types types = Types.instance(context);
         ct.addTaskListener(new Indifier(syms, names, types));
-        try {
-            ct.generate();
-        } catch (Throwable t) {
-            t.printStackTrace();
-            throw new AssertionError(
-                    String.format("Error thrown when compiling following code\n%s",
-                    source.source));
-        }
-        if (dc.diagFound) {
-            throw new AssertionError(
-                    String.format("Diags found when compiling following code\n%s\n\n%s",
-                    source.source, dc.printDiags()));
-        }
-        verifyBytecode(id);
+        verifyBytecode(comboTask.generate());
     }
 
-    void verifyBytecode(int id) {
-        File compiledTest = new File(String.format("Test%d.class", id));
-        try {
-            ClassFile cf = ClassFile.read(compiledTest);
+    void verifyBytecode(Result<Iterable<? extends JavaFileObject>> res) {
+        if (res.hasErrors()) {
+            fail("Diags found when compiling instance: " + res.compilationInfo());
+            return;
+        }
+        try (InputStream is = res.get().iterator().next().openInputStream()){
+            ClassFile cf = ClassFile.read(is);
             Method testMethod = null;
             for (Method m : cf.methods) {
                 if (m.getName(cf.constant_pool).equals("test")) {
@@ -279,12 +280,14 @@
                 }
             }
             if (testMethod == null) {
-                throw new Error("Test method not found");
+                fail("Test method not found");
+                return;
             }
             Code_attribute ea =
                     (Code_attribute)testMethod.attributes.get(Attribute.Code);
             if (testMethod == null) {
-                throw new Error("Code attribute for test() method not found");
+                fail("Code attribute for test() method not found");
+                return;
             }
 
             int bsmIdx = -1;
@@ -296,37 +299,39 @@
                             .constant_pool.get(i.getShort(1));
                     bsmIdx = indyInfo.bootstrap_method_attr_index;
                     if (!indyInfo.getNameAndTypeInfo().getType().equals("()V")) {
-                        throw new
-                            AssertionError("type mismatch for CONSTANT_InvokeDynamic_info");
+                        fail("type mismatch for CONSTANT_InvokeDynamic_info");
+                        return;
                     }
                 }
             }
             if (bsmIdx == -1) {
-                throw new Error("Missing invokedynamic in generated code");
+                fail("Missing invokedynamic in generated code");
+                return;
             }
 
             BootstrapMethods_attribute bsm_attr =
                     (BootstrapMethods_attribute)cf
                     .getAttribute(Attribute.BootstrapMethods);
             if (bsm_attr.bootstrap_method_specifiers.length != 1) {
-                throw new Error("Bad number of method specifiers " +
+                fail("Bad number of method specifiers " +
                         "in BootstrapMethods attribute");
+                return;
             }
             BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec =
                     bsm_attr.bootstrap_method_specifiers[0];
 
             if (bsm_spec.bootstrap_arguments.length != arity.arity) {
-                throw new Error("Bad number of static invokedynamic args " +
+                fail("Bad number of static invokedynamic args " +
                         "in BootstrapMethod attribute");
+                return;
             }
 
-            int count = 0;
-            for (StaticArgumentKind sak : saks) {
-                if (!sak.check(cf.constant_pool
-                        .get(bsm_spec.bootstrap_arguments[count]))) {
-                    throw new Error("Bad static argument value " + sak);
+            for (int i = 0 ; i < arity.arity ; i++) {
+                if (!saks[i].check(cf.constant_pool
+                        .get(bsm_spec.bootstrap_arguments[i]))) {
+                    fail("Bad static argument value " + saks[i]);
+                    return;
                 }
-                count++;
             }
 
             CONSTANT_MethodHandle_info bsm_handle =
@@ -334,7 +339,8 @@
                     .get(bsm_spec.bootstrap_method_ref);
 
             if (bsm_handle.reference_kind != RefKind.REF_invokeStatic) {
-                throw new Error("Bad kind on boostrap method handle");
+                fail("Bad kind on boostrap method handle");
+                return;
             }
 
             CONSTANT_Methodref_info bsm_ref =
@@ -342,88 +348,51 @@
                     .get(bsm_handle.reference_index);
 
             if (!bsm_ref.getClassInfo().getName().equals("Bootstrap")) {
-                throw new Error("Bad owner of boostrap method");
+                fail("Bad owner of boostrap method");
+                return;
             }
 
             if (!bsm_ref.getNameAndTypeInfo().getName().equals("bsm")) {
-                throw new Error("Bad boostrap method name");
+                fail("Bad boostrap method name");
+                return;
             }
 
             if (!bsm_ref.getNameAndTypeInfo()
                     .getType().equals(asBSMSignatureString())) {
-                throw new Error("Bad boostrap method type" +
+                fail("Bad boostrap method type" +
                         bsm_ref.getNameAndTypeInfo().getType() + " " +
                         asBSMSignatureString());
+                return;
             }
 
             LineNumberTable_attribute lnt =
                     (LineNumberTable_attribute)ea.attributes.get(Attribute.LineNumberTable);
 
             if (lnt == null) {
-                throw new Error("No LineNumberTable attribute");
+                fail("No LineNumberTable attribute");
+                return;
             }
             if (lnt.line_number_table_length != 3) {
-                throw new Error("Wrong number of entries in LineNumberTable");
+                fail("Wrong number of entries in LineNumberTable");
+                return;
             }
         } catch (Exception e) {
             e.printStackTrace();
-            throw new Error("error reading " + compiledTest +": " + e);
+            fail("error reading classfile: " + res.compilationInfo());
+            return;
         }
     }
 
     String asBSMSignatureString() {
         StringBuilder buf = new StringBuilder();
         buf.append("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;");
-        for (StaticArgumentKind sak : saks) {
-            buf.append(sak.bytecodeTypeStr);
+        for (int i = 0 ; i < arity.arity ; i++) {
+            buf.append(saks[i].bytecodeTypeStr);
         }
         buf.append(")Ljava/lang/invoke/CallSite;");
         return buf.toString();
     }
 
-    class JavaSource extends SimpleJavaFileObject {
-
-        static final String source_template = "import java.lang.invoke.*;\n" +
-                "class Bootstrap {\n" +
-                "   public static CallSite bsm(MethodHandles.Lookup lookup, " +
-                "String name, MethodType methodType #SARGS) {\n" +
-                "       return null;\n" +
-                "   }\n" +
-                "}\n" +
-                "class Test#ID {\n" +
-                "   void m() { }\n" +
-                "   void test() {\n" +
-                "      Object o = this; // marker statement \n" +
-                "      m();\n" +
-                "   }\n" +
-                "}";
-
-        String source;
-
-        JavaSource(int id) {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = source_template.replace("#SARGS", asSignatureString())
-                    .replace("#ID", String.valueOf(id));
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
-
-        String asSignatureString() {
-            int count = 0;
-            StringBuilder buf = new StringBuilder();
-            for (StaticArgumentKind sak : saks) {
-                buf.append(",");
-                buf.append(sak.sourceTypeStr);
-                buf.append(' ');
-                buf.append(String.format("x%d", count++));
-            }
-            return buf.toString();
-        }
-    }
-
     class Indifier extends TreeScanner<Void, Void> implements TaskListener {
 
         MethodSymbol bsm;
@@ -475,26 +444,4 @@
             return null;
         }
     }
-
-    static class DiagChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean diagFound;
-        ArrayList<String> diags = new ArrayList<>();
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            diags.add(diagnostic.getMessage(Locale.getDefault()));
-            diagFound = true;
-        }
-
-        String printDiags() {
-            StringBuilder buf = new StringBuilder();
-            for (String s : diags) {
-                buf.append(s);
-                buf.append("\n");
-            }
-            return buf.toString();
-        }
-    }
-
 }
--- a/langtools/test/tools/javac/lambda/TestLambdaToMethodStats.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/lambda/TestLambdaToMethodStats.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,34 +23,35 @@
 
 /*
  * @test
- * @bug 8013576
+ * @bug 8013576 8129962
  * @summary Add stat support to LambdaToMethod
- * @library ../lib
+ * @library /tools/javac/lib
  * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
  *          jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm TestLambdaToMethodStats
+ * @build combo.ComboTestHelper
+ * @run main TestLambdaToMethodStats
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import java.net.URI;
-import java.util.Arrays;
+import java.io.IOException;
 
 import javax.tools.Diagnostic;
 import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
 
-import com.sun.source.util.JavacTask;
 import com.sun.tools.javac.api.ClientCodeWrapper;
-import com.sun.tools.javac.util.JCDiagnostic;
 
-public class TestLambdaToMethodStats
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+import com.sun.tools.javac.util.List;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-    enum ExprKind {
+public class TestLambdaToMethodStats extends ComboInstance<TestLambdaToMethodStats> {
+
+    enum ExprKind implements ComboParameter {
         LAMBDA("()->null"),
         MREF1("this::g"),
         MREF2("this::h");
@@ -60,9 +61,14 @@
         ExprKind(String exprStr) {
             this.exprStr = exprStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return exprStr;
+        }
     }
 
-    enum TargetKind {
+    enum TargetKind implements ComboParameter {
         IMPLICIT(""),
         SERIALIZABLE("(A & java.io.Serializable)");
 
@@ -71,124 +77,89 @@
         TargetKind(String targetStr) {
             this.targetStr = targetStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return targetStr;
+        }
+    }
+
+    enum DiagnosticKind {
+        LAMBDA_STAT("compiler.note.lambda.stat", true, false),
+        MREF_STAT("compiler.note.mref.stat", false, false),
+        MREF_STAT1("compiler.note.mref.stat.1", false, true);
+
+        String code;
+        boolean lambda;
+        boolean bridge;
+
+        DiagnosticKind(String code, boolean lambda, boolean bridge) {
+            this.code = code;
+            this.lambda = lambda;
+            this.bridge = bridge;
+        }
     }
 
     public static void main(String... args) throws Exception {
-        for (ExprKind ek : ExprKind.values()) {
-            for (TargetKind tk : TargetKind.values()) {
-                pool.execute(new TestLambdaToMethodStats(ek, tk));
-            }
-        }
-
-        checkAfterExec(true);
+        new ComboTestHelper<TestLambdaToMethodStats>()
+                .withDimension("EXPR", (x, expr) -> x.ek = expr, ExprKind.values())
+                .withDimension("CAST", (x, target) -> x.tk = target, TargetKind.values())
+                .run(TestLambdaToMethodStats::new);
     }
 
     ExprKind ek;
     TargetKind tk;
-    JavaSource source;
-    DiagnosticChecker diagChecker;
-
 
-    TestLambdaToMethodStats(ExprKind ek, TargetKind tk) {
-        this.ek = ek;
-        this.tk = tk;
-        this.source = new JavaSource();
-        this.diagChecker = new DiagnosticChecker();
+    String template = "interface A {\n" +
+            "   Object o();\n" +
+            "}\n" +
+            "class Test {\n" +
+            "   A a = #{CAST}#{EXPR};\n" +
+            "   Object g() { return null; }\n" +
+            "   Object h(Object... o) { return null; }\n" +
+            "}";
+
+    @Override
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withOption("-XDdumpLambdaToMethodStats")
+                .withSourceFromTemplate(template)
+                .generate());
     }
 
-    class JavaSource extends SimpleJavaFileObject {
-
-        String template = "interface A {\n" +
-                          "   Object o();\n" +
-                          "}\n" +
-                          "class Test {\n" +
-                          "   A a = #C#E;\n" +
-                          "   Object g() { return null; }\n" +
-                          "   Object h(Object... o) { return null; }\n" +
-                          "}";
-
-        String source;
-
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = template.replaceAll("#E", ek.exprStr)
-                    .replaceAll("#C", tk.targetStr);
+    void check(Result<?> res) {
+        DiagnosticKind diag = null;
+        boolean altMetafactory = false;
+        for (DiagnosticKind dk : DiagnosticKind.values()) {
+            List<Diagnostic<? extends JavaFileObject>> jcDiag = res.diagnosticsForKey(dk.code);
+            if (jcDiag.nonEmpty()) {
+                diag = dk;
+                ClientCodeWrapper.DiagnosticSourceUnwrapper dsu =
+                        (ClientCodeWrapper.DiagnosticSourceUnwrapper)jcDiag.head;
+                altMetafactory = (Boolean)dsu.d.getArgs()[0];
+                break;
+            }
         }
 
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
+        if (diag == null) {
+            fail("No diagnostic found; " + res.compilationInfo());
         }
-    }
 
-    public void run() {
-        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
-                Arrays.asList("-XDdumpLambdaToMethodStats"),
-                null, Arrays.asList(source));
-        try {
-            ct.generate();
-        } catch (Throwable ex) {
-            throw new
-                AssertionError("Error thron when analyzing the following source:\n" +
-                    source.getCharContent(true));
-        }
-        check();
-    }
-
-    void check() {
-        checkCount.incrementAndGet();
-
-        boolean error = diagChecker.lambda !=
+        boolean error = diag.lambda !=
                 (ek == ExprKind.LAMBDA);
 
-        error |= diagChecker.bridge !=
+        error |= diag.bridge !=
                 (ek == ExprKind.MREF2);
 
-        error |= diagChecker.altMetafactory !=
+        error |= altMetafactory !=
                 (tk == TargetKind.SERIALIZABLE);
 
         if (error) {
-            throw new AssertionError("Bad stat diagnostic found for source\n" +
-                    "lambda = " + diagChecker.lambda + "\n" +
-                    "bridge = " + diagChecker.bridge + "\n" +
-                    "altMF = " + diagChecker.altMetafactory + "\n" +
-                    source.source);
-        }
-    }
-
-    static class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean altMetafactory;
-        boolean bridge;
-        boolean lambda;
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            try {
-                if (diagnostic.getKind() == Diagnostic.Kind.NOTE) {
-                    switch (diagnostic.getCode()) {
-                        case "compiler.note.lambda.stat":
-                            lambda = true;
-                            break;
-                        case "compiler.note.mref.stat":
-                            lambda = false;
-                            bridge = false;
-                            break;
-                        case "compiler.note.mref.stat.1":
-                            lambda = false;
-                            bridge = true;
-                            break;
-                        default:
-                            throw new AssertionError("unexpected note: " + diagnostic.getCode());
-                    }
-                    ClientCodeWrapper.DiagnosticSourceUnwrapper dsu =
-                        (ClientCodeWrapper.DiagnosticSourceUnwrapper)diagnostic;
-                    altMetafactory = (Boolean)dsu.d.getArgs()[0];
-                }
-            } catch (RuntimeException t) {
-                t.printStackTrace();
-                throw t;
-            }
+            fail("Bad stat diagnostic found for source\n" +
+                    "lambda = " + diag.lambda + "\n" +
+                    "bridge = " + diag.bridge + "\n" +
+                    "altMF = " + altMetafactory + "\n" +
+                    res.compilationInfo());
         }
     }
 }
--- a/langtools/test/tools/javac/lambda/bytecode/TestLambdaBytecode.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/lambda/bytecode/TestLambdaBytecode.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,18 +23,20 @@
 
 /*
  * @test
- * @bug 8009649
+ * @bug 8009649 8129962
  * @summary Lambda back-end should generate invokespecial for method handles referring to private instance methods
- * @library ../../lib
+ * @library /tools/javac/lib
  * @modules jdk.jdeps/com.sun.tools.classfile
  *          jdk.compiler/com.sun.tools.javac.api
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm TestLambdaBytecode
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main TestLambdaBytecode
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
 import com.sun.tools.classfile.Attribute;
 import com.sun.tools.classfile.BootstrapMethods_attribute;
 import com.sun.tools.classfile.ClassFile;
@@ -43,26 +45,22 @@
 import com.sun.tools.classfile.Instruction;
 import com.sun.tools.classfile.Method;
 
-import com.sun.tools.javac.api.JavacTaskImpl;
-
+import java.io.IOException;
+import java.io.InputStream;
 
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Locale;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-import javax.tools.Diagnostic;
 import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
 
-import static com.sun.tools.javac.jvm.ClassFile.*;
+public class TestLambdaBytecode extends ComboInstance<TestLambdaBytecode> {
 
-public class TestLambdaBytecode
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+    static final int MF_ARITY = 3;
+    static final String MH_SIG = "()V";
 
-    enum ClassKind {
+    enum ClassKind implements ComboParameter {
         CLASS("class"),
         INTERFACE("interface");
 
@@ -71,9 +69,14 @@
         ClassKind(String classStr) {
             this.classStr = classStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return classStr;
+        }
     }
 
-    enum AccessKind {
+    enum AccessKind implements ComboParameter {
         PUBLIC("public"),
         PRIVATE("private");
 
@@ -82,9 +85,14 @@
         AccessKind(String accessStr) {
             this.accessStr = accessStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return accessStr;
+        }
     }
 
-    enum StaticKind {
+    enum StaticKind implements ComboParameter {
         STATIC("static"),
         INSTANCE("");
 
@@ -93,9 +101,14 @@
         StaticKind(String staticStr) {
             this.staticStr = staticStr;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return staticStr;
+        }
     }
 
-    enum DefaultKind {
+    enum DefaultKind implements ComboParameter {
         DEFAULT("default"),
         NO_DEFAULT("");
 
@@ -104,15 +117,10 @@
         DefaultKind(String defaultStr) {
             this.defaultStr = defaultStr;
         }
-    }
 
-    enum ExprKind {
-        LAMBDA("Runnable r = ()->{ target(); };");
-
-        String exprString;
-
-        ExprKind(String exprString) {
-            this.exprString = exprString;
+        @Override
+        public String expand(String optParameter) {
+            return defaultStr;
         }
     }
 
@@ -155,83 +163,53 @@
                 return true;
             }
         }
-
-        String mods() {
-            StringBuilder buf = new StringBuilder();
-            buf.append(ak.accessStr);
-            buf.append(' ');
-            buf.append(sk.staticStr);
-            buf.append(' ');
-            buf.append(dk.defaultStr);
-            return buf.toString();
-        }
     }
 
     public static void main(String... args) throws Exception {
-        for (ClassKind ck : ClassKind.values()) {
-            for (AccessKind ak1 : AccessKind.values()) {
-                for (StaticKind sk1 : StaticKind.values()) {
-                    for (DefaultKind dk1 : DefaultKind.values()) {
-                        for (AccessKind ak2 : AccessKind.values()) {
-                            for (StaticKind sk2 : StaticKind.values()) {
-                                for (DefaultKind dk2 : DefaultKind.values()) {
-                                    for (ExprKind ek : ExprKind.values()) {
-                                        pool.execute(new TestLambdaBytecode(ck, ak1, ak2, sk1, sk2, dk1, dk2, ek));
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec();
+        new ComboTestHelper<TestLambdaBytecode>()
+                .withDimension("CLASSKIND", (x, ck) -> x.ck = ck, ClassKind.values())
+                .withArrayDimension("ACCESS", (x, acc, idx) -> x.accessKinds[idx] = acc, 2, AccessKind.values())
+                .withArrayDimension("STATIC", (x, sk, idx) -> x.staticKinds[idx] = sk, 2, StaticKind.values())
+                .withArrayDimension("DEFAULT", (x, dk, idx) -> x.defaultKinds[idx] = dk, 2, DefaultKind.values())
+                .run(TestLambdaBytecode::new, TestLambdaBytecode::init);
     }
 
+    ClassKind ck;
+    AccessKind[] accessKinds = new AccessKind[2];
+    StaticKind[] staticKinds = new StaticKind[2];
+    DefaultKind[] defaultKinds = new DefaultKind[2];
     MethodKind mk1, mk2;
-    ExprKind ek;
-    DiagChecker dc;
 
-    TestLambdaBytecode(ClassKind ck, AccessKind ak1, AccessKind ak2, StaticKind sk1,
-            StaticKind sk2, DefaultKind dk1, DefaultKind dk2, ExprKind ek) {
-        mk1 = new MethodKind(ck, ak1, sk1, dk1);
-        mk2 = new MethodKind(ck, ak2, sk2, dk2);
-        this.ek = ek;
-        dc = new DiagChecker();
+    void init() {
+        mk1 = new MethodKind(ck, accessKinds[0], staticKinds[0], defaultKinds[0]);
+        mk2 = new MethodKind(ck, accessKinds[1], staticKinds[1], defaultKinds[1]);
     }
 
-    public void run() {
-        int id = checkCount.incrementAndGet();
-        JavaSource source = new JavaSource(id);
-        JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc,
-                null, null, Arrays.asList(source));
-        try {
-            ct.generate();
-        } catch (Throwable t) {
-            t.printStackTrace();
-            throw new AssertionError(
-                    String.format("Error thrown when compiling following code\n%s",
-                    source.source));
-        }
-        if (dc.diagFound) {
+    String source_template =
+                "#{CLASSKIND} Test {\n" +
+                "   #{ACCESS[0]} #{STATIC[0]} #{DEFAULT[0]} void test() { Runnable r = ()->{ target(); }; }\n" +
+                "   #{ACCESS[1]} #{STATIC[1]} #{DEFAULT[1]} void target() { }\n" +
+                "}\n";
+
+    @Override
+    public void doWork() throws IOException {
+        verifyBytecode(newCompilationTask()
+                .withSourceFromTemplate(source_template)
+                .generate());
+    }
+
+    void verifyBytecode(Result<Iterable<? extends JavaFileObject>> res) {
+        if (res.hasErrors()) {
             boolean errorExpected = !mk1.isOK() || !mk2.isOK();
             errorExpected |= mk1.isStatic() && !mk2.isStatic();
 
             if (!errorExpected) {
-                throw new AssertionError(
-                        String.format("Diags found when compiling following code\n%s\n\n%s",
-                        source.source, dc.printDiags()));
+                fail("Diags found when compiling instance; " + res.compilationInfo());
             }
             return;
         }
-        verifyBytecode(id, source);
-    }
-
-    void verifyBytecode(int id, JavaSource source) {
-        File compiledTest = new File(String.format("Test%d.class", id));
-        try {
-            ClassFile cf = ClassFile.read(compiledTest);
+        try (InputStream is = res.get().iterator().next().openInputStream()) {
+            ClassFile cf = ClassFile.read(is);
             Method testMethod = null;
             for (Method m : cf.methods) {
                 if (m.getName(cf.constant_pool).equals("test")) {
@@ -240,12 +218,14 @@
                 }
             }
             if (testMethod == null) {
-                throw new Error("Test method not found");
+                fail("Test method not found");
+                return;
             }
             Code_attribute ea =
                     (Code_attribute)testMethod.attributes.get(Attribute.Code);
             if (testMethod == null) {
-                throw new Error("Code attribute for test() method not found");
+                fail("Code attribute for test() method not found");
+                return;
             }
 
             int bsmIdx = -1;
@@ -256,29 +236,34 @@
                          (CONSTANT_InvokeDynamic_info)cf
                             .constant_pool.get(i.getShort(1));
                     bsmIdx = indyInfo.bootstrap_method_attr_index;
-                    if (!indyInfo.getNameAndTypeInfo().getType().equals(makeIndyType(id))) {
-                        throw new
-                            AssertionError("type mismatch for CONSTANT_InvokeDynamic_info " + source.source + "\n" + indyInfo.getNameAndTypeInfo().getType() + "\n" + makeIndyType(id));
+                    if (!indyInfo.getNameAndTypeInfo().getType().equals(makeIndyType())) {
+                        fail("type mismatch for CONSTANT_InvokeDynamic_info " +
+                                res.compilationInfo() + "\n" + indyInfo.getNameAndTypeInfo().getType() +
+                                "\n" + makeIndyType());
+                        return;
                     }
                 }
             }
             if (bsmIdx == -1) {
-                throw new Error("Missing invokedynamic in generated code");
+                fail("Missing invokedynamic in generated code");
+                return;
             }
 
             BootstrapMethods_attribute bsm_attr =
                     (BootstrapMethods_attribute)cf
                     .getAttribute(Attribute.BootstrapMethods);
             if (bsm_attr.bootstrap_method_specifiers.length != 1) {
-                throw new Error("Bad number of method specifiers " +
+                fail("Bad number of method specifiers " +
                         "in BootstrapMethods attribute");
+                return;
             }
             BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec =
                     bsm_attr.bootstrap_method_specifiers[0];
 
             if (bsm_spec.bootstrap_arguments.length != MF_ARITY) {
-                throw new Error("Bad number of static invokedynamic args " +
+                fail("Bad number of static invokedynamic args " +
                         "in BootstrapMethod attribute");
+                return;
             }
 
             CONSTANT_MethodHandle_info mh =
@@ -294,74 +279,27 @@
             }
 
             if (!kindOK) {
-                throw new Error("Bad invoke kind in implementation method handle");
+                fail("Bad invoke kind in implementation method handle");
+                return;
             }
 
             if (!mh.getCPRefInfo().getNameAndTypeInfo().getType().toString().equals(MH_SIG)) {
-                throw new Error("Type mismatch in implementation method handle");
+                fail("Type mismatch in implementation method handle");
+                return;
             }
         } catch (Exception e) {
             e.printStackTrace();
-            throw new Error("error reading " + compiledTest +": " + e);
+            fail("error reading " + res.compilationInfo() + ": " + e);
         }
     }
-    String makeIndyType(int id) {
+
+    String makeIndyType() {
         StringBuilder buf = new StringBuilder();
         buf.append("(");
         if (!mk2.isStatic()) {
-            buf.append(String.format("LTest%d;", id));
+            buf.append("LTest;");
         }
         buf.append(")Ljava/lang/Runnable;");
         return buf.toString();
     }
-
-    static final int MF_ARITY = 3;
-    static final String MH_SIG = "()V";
-
-    class JavaSource extends SimpleJavaFileObject {
-
-        static final String source_template =
-                "#CK Test#ID {\n" +
-                "   #MOD1 void test() { #EK }\n" +
-                "   #MOD2 void target() { }\n" +
-                "}\n";
-
-        String source;
-
-        JavaSource(int id) {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = source_template.replace("#CK", mk1.ck.classStr)
-                    .replace("#MOD1", mk1.mods())
-                    .replace("#MOD2", mk2.mods())
-                    .replace("#EK", ek.exprString)
-                    .replace("#ID", String.valueOf(id));
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
-    }
-
-    static class DiagChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean diagFound;
-        ArrayList<String> diags = new ArrayList<>();
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            diags.add(diagnostic.getMessage(Locale.getDefault()));
-            diagFound = true;
-        }
-
-        String printDiags() {
-            StringBuilder buf = new StringBuilder();
-            for (String s : diags) {
-                buf.append(s);
-                buf.append("\n");
-            }
-            return buf.toString();
-        }
-    }
-
 }
--- a/langtools/test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,34 +23,36 @@
 
 /*
  * @test
- * @bug 8003280 8006694
+ * @bug 8003280 8006694 8129962
  * @summary Add lambda tests
  *  Automatic test for checking correctness of structural most specific test routine
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../../lib
+ * @library /tools/javac/lib
  * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
  *          jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm/timeout=600 StructuralMostSpecificTest
+ * @build combo.ComboTestHelper
+
+ * @run main StructuralMostSpecificTest
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import java.net.URI;
-import java.util.Arrays;
+import javax.lang.model.element.Element;
 import javax.tools.Diagnostic;
 import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
 import com.sun.tools.javac.api.ClientCodeWrapper;
 import com.sun.tools.javac.util.JCDiagnostic;
+import com.sun.tools.javac.util.List;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-public class StructuralMostSpecificTest
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+public class StructuralMostSpecificTest extends ComboInstance<StructuralMostSpecificTest> {
 
-    enum RetTypeKind {
+    enum RetTypeKind implements ComboParameter {
         SHORT("short"),
         INT("int"),
         OBJECT("Object"),
@@ -76,9 +78,13 @@
                 /* INTEGER */ { false , false , true   , true    , false , false },
                 /* VOID */    { false , false , false  , false   , true  , true  },
                 /* J_L_VOID */{ false , false , true   , false   , false , true  } };
+
+        public String expand(String optParameter) {
+            return retTypeStr;
+        }
     }
 
-    enum ArgTypeKind {
+    enum ArgTypeKind implements ComboParameter {
         SHORT("short"),
         INT("int"),
         BOOLEAN("boolean"),
@@ -91,9 +97,13 @@
         ArgTypeKind(String typeStr) {
             this.argTypeStr = typeStr;
         }
+
+        public String expand(String optParameter) {
+            return argTypeStr;
+        }
     }
 
-    enum ExceptionKind {
+    enum ExceptionKind implements ComboParameter {
         NONE(""),
         EXCEPTION("throws Exception"),
         SQL_EXCEPTION("throws java.sql.SQLException"),
@@ -104,9 +114,13 @@
         ExceptionKind(String exceptionStr) {
             this.exceptionStr = exceptionStr;
         }
+
+        public String expand(String optParameter) {
+            return exceptionStr;
+        }
     }
 
-    enum LambdaReturnKind {
+    enum LambdaReturnKind implements ComboParameter {
         VOID("return;"),
         SHORT("return (short)0;"),
         INT("return 0;"),
@@ -144,118 +158,72 @@
                 /* INTEGER */ { false , false , true    , false   , false },
                 /* VOID */    { false , false , false   , false   , false },
                 /* J_L_VOID */{ true  , false , false   , false   , false } };
-    }
 
-    public static void main(String... args) throws Exception {
-        for (LambdaReturnKind lrk : LambdaReturnKind.values()) {
-            for (RetTypeKind rk1 : RetTypeKind.values()) {
-                for (RetTypeKind rk2 : RetTypeKind.values()) {
-                    for (ExceptionKind ek1 : ExceptionKind.values()) {
-                        for (ExceptionKind ek2 : ExceptionKind.values()) {
-                            for (ArgTypeKind ak11 : ArgTypeKind.values()) {
-                                for (ArgTypeKind ak12 : ArgTypeKind.values()) {
-                                    pool.execute(
-                                        new StructuralMostSpecificTest(lrk, rk1,
-                                            rk2, ek1, ek2, ak11, ak12));
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec();
-    }
-
-    LambdaReturnKind lrk;
-    RetTypeKind rt1, rt2;
-    ArgTypeKind ak1, ak2;
-    ExceptionKind ek1, ek2;
-    JavaSource source;
-    DiagnosticChecker diagChecker;
-
-    StructuralMostSpecificTest(LambdaReturnKind lrk, RetTypeKind rt1, RetTypeKind rt2,
-            ExceptionKind ek1, ExceptionKind ek2, ArgTypeKind ak1, ArgTypeKind ak2) {
-        this.lrk = lrk;
-        this.rt1 = rt1;
-        this.rt2 = rt2;
-        this.ek1 = ek1;
-        this.ek2 = ek2;
-        this.ak1 = ak1;
-        this.ak2 = ak2;
-        this.source = new JavaSource();
-        this.diagChecker = new DiagnosticChecker();
-    }
-
-    class JavaSource extends SimpleJavaFileObject {
-
-        String template = "interface SAM1 {\n" +
-                          "   #R1 m(#A1 a1) #E1;\n" +
-                          "}\n" +
-                          "interface SAM2 {\n" +
-                          "   #R2 m(#A2 a1) #E2;\n" +
-                          "}\n" +
-                          "class Test {\n" +
-                          "   void m(SAM1 s) { }\n" +
-                          "   void m(SAM2 s) { }\n" +
-                          "   { m((#A1 x)->{ #LR }); }\n" +
-                          "}\n";
-
-        String source;
-
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = template.replaceAll("#LR", lrk.retStr)
-                    .replaceAll("#R1", rt1.retTypeStr)
-                    .replaceAll("#R2", rt2.retTypeStr)
-                    .replaceAll("#A1", ak1.argTypeStr)
-                    .replaceAll("#A2", ak2.argTypeStr)
-                    .replaceAll("#E1", ek1.exceptionStr)
-                    .replaceAll("#E2", ek2.exceptionStr);
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
+        public String expand(String optParameter) {
+            return retStr;
         }
     }
 
-    public void run() {
-        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
-                Arrays.asList("-XDverboseResolution=all,-predef,-internal,-object-init"),
-                null, Arrays.asList(source));
-        try {
-            ct.analyze();
-        } catch (Throwable ex) {
-            throw new
-                AssertionError("Error thron when analyzing the following source:\n" +
-                    source.getCharContent(true));
-        }
-        check();
+    static final String sourceTemplate =
+            "interface SAM1 {\n" +
+            "   #{RET[0]} m(#{ARG[0]} a1) #{EX[0]};\n" +
+            "}\n" +
+            "interface SAM2 {\n" +
+            "   #{RET[1]} m(#{ARG[1]} a1) #{EX[1]};\n" +
+            "}\n" +
+            "class Test {\n" +
+            "   void m(SAM1 s) { }\n" +
+            "   void m(SAM2 s) { }\n" +
+            "   { m((#{ARG[0]} x)->{ #{EXPR} }); }\n" +
+            "}\n";
+
+    public static void main(String... args) throws Exception {
+        new ComboTestHelper<StructuralMostSpecificTest>()
+                .withFilter(StructuralMostSpecificTest::hasSameArguments)
+                .withFilter(StructuralMostSpecificTest::hasCompatibleReturns)
+                .withFilter(StructuralMostSpecificTest::hasSameOverloadPhase)
+                .withDimension("EXPR", (x, expr) -> x.lambdaReturnKind = expr, LambdaReturnKind.values())
+                .withArrayDimension("RET", (x, ret, idx) -> x.returnType[idx] = ret, 2, RetTypeKind.values())
+                .withArrayDimension("EX", 2, ExceptionKind.values())
+                .withArrayDimension("ARG", (x, arg, idx) -> x.argumentKind[idx] = arg, 2, ArgTypeKind.values())
+                .run(StructuralMostSpecificTest::new);
     }
 
-    void check() {
-        checkCount.incrementAndGet();
+    LambdaReturnKind lambdaReturnKind;
+    RetTypeKind[] returnType = new RetTypeKind[2];
+    ArgTypeKind[] argumentKind = new ArgTypeKind[2];
 
-        if (ak1 != ak2)
-            return;
+    boolean hasSameArguments() {
+        return argumentKind[0] == argumentKind[1];
+    }
+
+    boolean hasCompatibleReturns() {
+        return lambdaReturnKind.compatibleWith(returnType[0]) &&
+                lambdaReturnKind.compatibleWith(returnType[1]);
+    }
 
-        if (!lrk.compatibleWith(rt1) || !lrk.compatibleWith(rt2))
-            return;
+    boolean hasSameOverloadPhase() {
+        return lambdaReturnKind.needsConversion(returnType[0]) == lambdaReturnKind.needsConversion(returnType[1]);
+    }
 
-        if (lrk.needsConversion(rt1) != lrk.needsConversion(rt2))
-            return;
+    @Override
+    public void doWork() throws Throwable {
+        check(newCompilationTask()
+                .withSourceFromTemplate(sourceTemplate)
+                .withOption("-XDverboseResolution=all,-predef,-internal,-object-init")
+                .analyze());
+    }
 
-        boolean m1MoreSpecific = rt1.moreSpecificThan(rt2);
-        boolean m2MoreSpecific = rt2.moreSpecificThan(rt1);
+    void check(Result<Iterable<? extends Element>> result) {
+        boolean m1MoreSpecific = returnType[0].moreSpecificThan(returnType[1]);
+        boolean m2MoreSpecific = returnType[1].moreSpecificThan(returnType[0]);
 
         boolean ambiguous = (m1MoreSpecific == m2MoreSpecific);
 
-        if (ambiguous != diagChecker.ambiguityFound) {
-            throw new Error("invalid diagnostics for source:\n" +
-                source.getCharContent(true) +
-                "\nAmbiguity found: " + diagChecker.ambiguityFound +
+        if (ambiguous != ambiguityFound(result)) {
+            fail("invalid diagnostics for combo:\n" +
+                result.compilationInfo() + "\n" +
+                "\nAmbiguity found: " + ambiguityFound(result) +
                 "\nm1 more specific: " + m1MoreSpecific +
                 "\nm2 more specific: " + m2MoreSpecific +
                 "\nexpected ambiguity: " + ambiguous);
@@ -263,44 +231,32 @@
 
         if (!ambiguous) {
             String sigToCheck = m1MoreSpecific ? "m(SAM1)" : "m(SAM2)";
-            if (!sigToCheck.equals(diagChecker.mostSpecificSig)) {
-                throw new Error("invalid most specific method selected:\n" +
-                source.getCharContent(true) +
-                "\nMost specific found: " + diagChecker.mostSpecificSig +
-                "\nm1 more specific: " + m1MoreSpecific +
-                "\nm2 more specific: " + m2MoreSpecific);
+            if (!sigToCheck.equals(mostSpecificSignature(result))) {
+                fail("invalid most specific method selected:\n" +
+                        result.compilationInfo() + "\n" +
+                        "\nMost specific found: " + mostSpecificSignature(result) +
+                        "\nm1 more specific: " + m1MoreSpecific +
+                        "\nm2 more specific: " + m2MoreSpecific);
             }
         }
     }
 
-    static class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean ambiguityFound;
-        String mostSpecificSig;
+    boolean ambiguityFound(Result<Iterable<? extends Element>> result) {
+        return result.containsKey("compiler.err.ref.ambiguous");
+    }
 
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            try {
-                if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
-                        diagnostic.getCode().equals("compiler.err.ref.ambiguous")) {
-                    ambiguityFound = true;
-                } else if (diagnostic.getKind() == Diagnostic.Kind.NOTE &&
-                        diagnostic.getCode()
-                        .equals("compiler.note.verbose.resolve.multi")) {
-                    ClientCodeWrapper.DiagnosticSourceUnwrapper dsu =
-                        (ClientCodeWrapper.DiagnosticSourceUnwrapper)diagnostic;
-                    JCDiagnostic.MultilineDiagnostic mdiag =
-                        (JCDiagnostic.MultilineDiagnostic)dsu.d;
-                    int mostSpecificIndex = (Integer)mdiag.getArgs()[2];
-                    mostSpecificSig =
-                        ((JCDiagnostic)mdiag.getSubdiagnostics()
-                            .get(mostSpecificIndex)).getArgs()[1].toString();
-                }
-            } catch (RuntimeException t) {
-                t.printStackTrace();
-                throw t;
-            }
+    String mostSpecificSignature(Result<Iterable<? extends Element>> result) {
+        List<Diagnostic<? extends JavaFileObject>> rsDiag =
+                result.diagnosticsForKey("compiler.note.verbose.resolve.multi");
+        if (rsDiag.nonEmpty()) {
+            ClientCodeWrapper.DiagnosticSourceUnwrapper dsu =
+                        (ClientCodeWrapper.DiagnosticSourceUnwrapper)rsDiag.head;
+            JCDiagnostic.MultilineDiagnostic mdiag =
+                (JCDiagnostic.MultilineDiagnostic)dsu.d;
+            int mostSpecificIndex = (Integer)mdiag.getArgs()[2];
+            return mdiag.getSubdiagnostics().get(mostSpecificIndex).getArgs()[1].toString();
+        } else {
+            return null;
         }
     }
-
 }
--- a/langtools/test/tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,31 +23,31 @@
 
 /**
  * @test
- * @bug 8003280 8006694
+ * @bug 8003280 8006694 8129962
  * @summary Add lambda tests
  *  perform automated checks in type inference in lambda expressions
  *  in different contexts
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
  * @compile  TypeInferenceComboTest.java
- * @run main/othervm/timeout=360 TypeInferenceComboTest
+ * @run main TypeInferenceComboTest
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
 
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-public class TypeInferenceComboTest
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+public class TypeInferenceComboTest extends ComboInstance<TypeInferenceComboTest> {
     enum Context {
         ASSIGNMENT("SAM#Type s = #LBody;"),
         METHOD_CALL("#GenericDeclKind void method1(SAM#Type s) { }\n" +
@@ -221,82 +221,21 @@
         }
     }
 
-    boolean checkTypeInference() {
-        if (parameterType == TypeKind.VOID) {
-            if (lambdaBodyType != LambdaBody.RETURN_VOID)
-                return false;
-        }
-        else if (lambdaBodyType != LambdaBody.RETURN_ARG)
-            return false;
-
-        return true;
-    }
-
-    String templateStr = "#C\n" +
-                         "interface SAM2 {\n" +
-                         "    SAM m();\n" +
-                         "}\n";
-    SourceFile samSourceFile = new SourceFile("Sam.java", templateStr) {
-        public String toString() {
-            return template.replaceAll("#C",
-                    samKind.getSam(parameterType, returnType));
-        }
-    };
-
-    SourceFile clientSourceFile = new SourceFile("Client.java",
-                                                 "class Client { \n" +
-                                                 "    #Context\n" +
-                                                 "}") {
-        public String toString() {
-            return template.replaceAll("#Context",
-                    context.getContext(samKind, samTargetType, keyword,
-                    parameterType, returnType, lambdaKind, parameterKind,
-                    genericDeclKind, lambdaBodyType));
-        }
-    };
-
-    public void run() {
-        DiagnosticChecker dc = new DiagnosticChecker();
-        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), dc,
-                null, null, Arrays.asList(samSourceFile, clientSourceFile));
-        try {
-            ct.analyze();
-        } catch (Throwable t) {
-            processException(t);
-        }
-        if (dc.errorFound == checkTypeInference()) {
-            throw new AssertionError(samSourceFile + "\n\n" +
-                    clientSourceFile + "\n" + parameterType + " " + returnType);
-        }
-    }
-
-    abstract class SourceFile extends SimpleJavaFileObject {
-
-        protected String template;
-
-        public SourceFile(String filename, String template) {
-            super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
-            this.template = template;
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return toString();
-        }
-
-        public abstract String toString();
-    }
-
-    static class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        boolean errorFound = false;
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errorFound = true;
-            }
-        }
+    public static void main(String[] args) {
+        new ComboTestHelper<TypeInferenceComboTest>()
+                .withFilter(TypeInferenceComboTest::badTestFilter)
+                .withFilter(TypeInferenceComboTest::redundantTestFilter)
+                .withDimension("SAM", (x, sam) -> x.samKind = sam, SamKind.values())
+                .withDimension("SAMTARGET", (x, target) -> x.samTargetType = target, TypeKind.values())
+                .withDimension("PARAMTYPE", (x, param) -> x.parameterType = param, TypeKind.values())
+                .withDimension("RETTYPE", (x, ret) -> x.returnType = ret, TypeKind.values())
+                .withDimension("CTX", (x, ctx) -> x.context = ctx, Context.values())
+                .withDimension("LAMBDABODY", (x, body) -> x.lambdaBodyType = body, LambdaBody.values())
+                .withDimension("LAMBDAKIND", (x, lambda) -> x.lambdaKind = lambda, LambdaKind.values())
+                .withDimension("PARAMKIND", (x, param) -> x.parameterKind = param, ParameterKind.values())
+                .withDimension("KEYWORD", (x, kw) -> x.keyword = kw, Keyword.values())
+                .withDimension("GENDECL", (x, gk) -> x.genericDeclKind = gk, GenericDeclKind.values())
+                .run(TypeInferenceComboTest::new);
     }
 
     SamKind samKind;
@@ -310,84 +249,75 @@
     Keyword keyword;
     GenericDeclKind genericDeclKind;
 
-    TypeInferenceComboTest(SamKind sk, TypeKind samTargetT, TypeKind parameterT,
-            TypeKind returnT, LambdaBody lb, Context c, LambdaKind lk,
-            ParameterKind pk, Keyword kw, GenericDeclKind gdk) {
-        samKind = sk;
-        samTargetType = samTargetT;
-        parameterType = parameterT;
-        returnType = returnT;
-        context = c;
-        lambdaKind = lk;
-        parameterKind = pk;
-        keyword = kw;
-        lambdaBodyType = lb;
-        genericDeclKind = gdk;
+    boolean badTestFilter() {
+        if (samKind == SamKind.NON_GENERIC) {
+            return (parameterType != TypeKind.GENERIC && returnType != TypeKind.GENERIC);
+        } else {
+            return (samTargetType != TypeKind.VOID &&
+                   samTargetType != TypeKind.INT &&
+                   samTargetType != TypeKind.GENERIC &&
+                   (parameterType == TypeKind.GENERIC ||
+                   returnType == TypeKind.GENERIC));
+        }
     }
 
-    public static void main(String[] args) throws Exception {
-        for(Context ct : Context.values()) {
-            for (TypeKind returnT : TypeKind.values()) {
-                for (TypeKind parameterT : TypeKind.values()) {
-                    for(LambdaBody lb : LambdaBody.values()) {
-                        for (ParameterKind parameterK : ParameterKind.values()) {
-                            for(LambdaKind lambdaK : LambdaKind.values()) {
-                                for (SamKind sk : SamKind.values()) {
-                                    if (sk == SamKind.NON_GENERIC) {
-                                        generateNonGenericSAM(ct, returnT,
-                                                parameterT, lb, parameterK,
-                                                lambdaK, sk);
-                                    }
-                                    else if (sk == SamKind.GENERIC) {
-                                        generateGenericSAM(ct, returnT,
-                                                parameterT, lb, parameterK,
-                                                lambdaK, sk);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec(false);
-    }
-
-    static void generateNonGenericSAM(Context ct, TypeKind returnT,
-            TypeKind parameterT, LambdaBody lb, ParameterKind parameterK,
-            LambdaKind lambdaK, SamKind sk) {
-        if(parameterT != TypeKind.GENERIC && returnT != TypeKind.GENERIC ) {
-            pool.execute(new TypeInferenceComboTest(sk, null, parameterT,
-                    returnT, lb, ct, lambdaK, parameterK, null, null));
+    boolean redundantTestFilter() {
+        if (samKind == SamKind.NON_GENERIC) {
+            return keyword.ordinal() == 0 && samTargetType.ordinal() == 0 && genericDeclKind.ordinal() == 0;
+        } else {
+            return context == Context.METHOD_CALL || genericDeclKind.ordinal() == 0;
         }
     }
 
-    static void generateGenericSAM(Context ct, TypeKind returnT,
-            TypeKind parameterT, LambdaBody lb, ParameterKind parameterK,
-            LambdaKind lambdaK, SamKind sk) {
-        for (Keyword kw : Keyword.values()) {
-            for (TypeKind samTargetT : TypeKind.values()) {
-                if(samTargetT != TypeKind.VOID &&
-                   samTargetT != TypeKind.INT &&
-                   samTargetT != TypeKind.GENERIC &&
-                   (parameterT == TypeKind.GENERIC ||
-                   returnT == TypeKind.GENERIC)) {
-                    if(ct != Context.METHOD_CALL) {
-                        pool.execute(
-                            new TypeInferenceComboTest(sk, samTargetT, parameterT,
-                                returnT, lb, ct, lambdaK, parameterK, kw, null));
-                    } else {//Context.METHOD_CALL
-                        for (GenericDeclKind gdk :
-                                GenericDeclKind.values())
-                            pool.execute(
-                                    new TypeInferenceComboTest(sk, samTargetT,
-                                    parameterT, returnT, lb, ct, lambdaK,
-                                    parameterK, kw, gdk));
-                    }
-                }
-            }
-         }
+    String sam_template = "#{SAM}\n" +
+                         "interface SAM2 {\n" +
+                         "    SAM m();\n" +
+                         "}\n";
+
+
+    String client_template = "class Client { \n" +
+                             "    #{CONTEXT}\n" +
+                             "}";
+
+    @Override
+    public void doWork() throws IOException {
+        Result<?> res = newCompilationTask()
+                .withSourceFromTemplate("Sam", sam_template, this::samClass)
+                .withSourceFromTemplate("Client", client_template, this::clientContext)
+                .analyze();
+
+        if (res.hasErrors() == checkTypeInference()) {
+            fail("Unexpected compilation output when compiling instance: " + res.compilationInfo());
+        }
     }
 
+    ComboParameter samClass(String parameterName) {
+        switch (parameterName) {
+            case "SAM":
+                return new ComboParameter.Constant<>(samKind.getSam(parameterType, returnType));
+            default:
+                return null;
+        }
+    }
+
+    ComboParameter clientContext(String parameterName) {
+        switch (parameterName) {
+            case "CONTEXT":
+                return new ComboParameter.Constant<>(context.getContext(samKind, samTargetType,
+                        keyword, parameterType, returnType, lambdaKind, parameterKind, genericDeclKind, lambdaBodyType));
+            default:
+                return null;
+        }
+    }
+
+    boolean checkTypeInference() {
+        if (parameterType == TypeKind.VOID) {
+            if (lambdaBodyType != LambdaBody.RETURN_VOID)
+                return false;
+        }
+        else if (lambdaBodyType != LambdaBody.RETURN_ARG)
+            return false;
+
+        return true;
+    }
 }
--- a/langtools/test/tools/javac/lib/JavacTestingAbstractThreadedTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, 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.PrintWriter;
-import java.io.StringWriter;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.tools.JavaCompiler;
-import javax.tools.StandardJavaFileManager;
-import javax.tools.ToolProvider;
-
-/**
- * An abstract superclass for threaded tests.
- *
- * This class will try to read a property named test.concurrency.
- * The property can be provided by passing this option to jtreg:
- * -javaoption:-Dtest.concurrency=#
- *
- * If the property is not set the class will use a heuristic to determine the
- * maximum number of threads that can be fired to execute a given test.
- *
- * This code will have to be revisited if jprt starts using concurrency for
- * for running jtreg tests.
- */
-public abstract class JavacTestingAbstractThreadedTest {
-
-    protected static AtomicInteger numberOfThreads = new AtomicInteger();
-
-    protected static int getThreadPoolSize() {
-        Integer testConc = Integer.getInteger("test.concurrency");
-        if (testConc != null) return testConc;
-        int cores = Runtime.getRuntime().availableProcessors();
-        numberOfThreads.set(Math.max(2, Math.min(8, cores / 2)));
-        return numberOfThreads.get();
-    }
-
-    protected static void checkAfterExec() throws InterruptedException {
-        checkAfterExec(true);
-    };
-
-    protected static boolean throwAssertionOnError = true;
-
-    protected static boolean printAll = false;
-
-    protected static StringWriter errSWriter = new StringWriter();
-    protected static PrintWriter errWriter = new PrintWriter(errSWriter);
-
-    protected static StringWriter outSWriter = new StringWriter();
-    protected static PrintWriter outWriter = new PrintWriter(outSWriter);
-
-    protected static void checkAfterExec(boolean printCheckCount)
-            throws InterruptedException {
-        pool.shutdown();
-        pool.awaitTermination(15, TimeUnit.MINUTES);
-        if (errCount.get() > 0) {
-            if (throwAssertionOnError) {
-                closePrinters();
-                System.err.println(errSWriter.toString());
-                throw new AssertionError(
-                    String.format("%d errors found", errCount.get()));
-            } else {
-                System.err.println(
-                        String.format("%d errors found", errCount.get()));
-            }
-        } else if (printCheckCount) {
-            outWriter.println("Total check executed: " + checkCount.get());
-        }
-        /*
-         * This output is for supporting debugging. It does not mean that a given
-         * test had executed that number of threads concurrently. The value printed
-         * here is the maximum possible amount.
-         */
-        closePrinters();
-        if (printAll) {
-            System.out.println(errSWriter.toString());
-            System.out.println(outSWriter.toString());
-        }
-        System.out.println("Total number of threads in thread pool: " +
-                numberOfThreads.get());
-    }
-
-    protected static void closePrinters() {
-        errWriter.close();
-        outWriter.close();
-    }
-
-    protected static void processException(Throwable t) {
-        errCount.incrementAndGet();
-        t.printStackTrace(errWriter);
-        pool.shutdown();
-    }
-
-    //number of checks executed
-    protected static AtomicInteger checkCount = new AtomicInteger();
-
-    //number of errors found while running combo tests
-    protected static AtomicInteger errCount = new AtomicInteger();
-
-    //create default shared JavaCompiler - reused across multiple compilations
-    protected static JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
-
-    protected static ExecutorService pool = Executors.newFixedThreadPool(
-            getThreadPoolSize(), new ThreadFactory() {
-        @Override
-        public Thread newThread(Runnable r) {
-            Thread t = new Thread(r);
-            t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
-                @Override
-                public void uncaughtException(Thread t, Throwable e) {
-                    pool.shutdown();
-                    errCount.incrementAndGet();
-                    e.printStackTrace(System.err);
-                }
-            });
-            return t;
-        }
-    });
-
-    /*
-     * File manager is not thread-safe so it cannot be re-used across multiple
-     * threads. However we cache per-thread FileManager to avoid excessive
-     * object creation
-     */
-    protected static final ThreadLocal<StandardJavaFileManager> fm =
-        new ThreadLocal<StandardJavaFileManager>() {
-            @Override protected StandardJavaFileManager initialValue() {
-                return comp.getStandardFileManager(null, null, null);
-            }
-        };
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lib/combo/ComboInstance.java	Mon Aug 31 17:33:34 2015 +0100
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package combo;
+
+import javax.tools.StandardJavaFileManager;
+import java.util.Optional;
+
+/**
+ * This class is the common superclass of all combo test instances. It defines few helper methods
+ * to build compilation tasks using the shared context object, as well as entry points for
+ * signalling test failures.
+ */
+public abstract class ComboInstance<X extends ComboInstance<X>> {
+
+    /** The test instance result status. */
+    private ResultStatus resultStatus = ResultStatus.PASSED;
+
+    /** The test instance execution environment. */
+    private ComboTestHelper<X>.Env env;
+
+    /**
+     * Entry point for executing a combo test instance; first, the test environment is saved
+     * in the corresponding field, then the instance is run (see {@link ComboInstance#doWork()}.
+     * During execution, the result status will be updated to match the test outcome.
+     */
+    final void run(ComboTestHelper<X>.Env env) {
+        try {
+            this.env = env;
+            doWork();
+            if (resultStatus.isSuccess()) {
+                env.info().passCount++;
+            }
+        } catch (Throwable ex) {
+            resultStatus = ResultStatus.ERROR;
+            env.info().errCount++;
+            env.info().lastError = Optional.of(ex);
+        } finally {
+            this.env = null;
+        }
+    }
+
+    /**
+     * Retrieve a unique ID associated with this test instance.
+     */
+    public int id() {
+        return env.info().comboCount;
+    }
+
+    /**
+     * Retrieve shared file manager.
+     */
+    public StandardJavaFileManager fileManager() {
+        return env.fileManager();
+    }
+
+    /**
+     * Create a new compilation task using shared compilation context.
+     */
+    protected ComboTask newCompilationTask() {
+        return new ComboTask(env);
+    }
+
+    /**
+     * Main test execution entry point; subclasses must implement this method to define the test
+     * logic.
+     */
+    protected abstract void doWork() throws Throwable;
+
+    /**
+     * Report a test failure.
+     */
+    protected void fail() {
+        //dump some default info (such as dimension bindings)
+        fail("Combo instance failed; " + env.bindings);
+    }
+
+    /**
+     * Report a test failure with corresponding failure message.
+     */
+    protected void fail(String msg) {
+        resultStatus = ResultStatus.FAILED;
+        env.info().failCount++;
+        env.info().lastFailure = Optional.of(msg);
+    }
+
+    /**
+     * The status associated with this test instance execution.
+     */
+    enum ResultStatus {
+        /** Test passed. */
+        PASSED(true),
+        /** Test failed. */
+        FAILED(false),
+        /** Test thrown unexpected error/exception. */
+        ERROR(false);
+
+        boolean success;
+
+        ResultStatus(boolean success) {
+            this.success = success;
+        }
+
+        boolean isSuccess() {
+            return success;
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lib/combo/ComboParameter.java	Mon Aug 31 17:33:34 2015 +0100
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package combo;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A combo parameter represents an 'hole' in a template that can be replaced with a given string.
+ * The schema of such holes is defined in {@link ComboParameter#pattern}; the main routine for
+ * replacing holes in a template scheme is {@link ComboParameter#expandTemplate(String, Resolver)}.
+ */
+public interface ComboParameter {
+
+    /**
+     * A combo parameter can take the form:
+     * <p>
+     * #{MAJOR}
+     * #{MAJOR.}
+     * #{MAJOR.MINOR}
+     * <p>
+     * where MAJOR can be IDENTIFIER or IDENTIFIER[NUMERIC_INDEX]
+     * and MINOR can be an identifier.
+     */
+    Pattern pattern = Pattern.compile("#\\{([A-Z_][A-Z0-9_]*(?:\\[\\d+\\])?)(?:\\.([A-Z0-9_]*))?\\}");
+
+    /**
+     * Entry point for the customizable replacement logic. Subclasses must implement this method to
+     * specify how a given template hole should be expanded. An optional contextual argument is passed
+     * in as parameter, to make expansion more flexible.
+     */
+    String expand(String optParameter);
+
+    /**
+     * Helper class for defining 'constant' combo parameters - i.e. parameters that always expand
+     * as a given string value - regardless of the context.
+     */
+    class Constant<D> implements ComboParameter {
+
+        D data;
+
+        public Constant(D data) {
+            this.data = data;
+        }
+
+        @Override
+        public String expand(String _unused) {
+            return String.valueOf(data);
+        }
+    }
+
+    /**
+     * Helper interface used to lookup parameters given a parameter name.
+     */
+    interface Resolver {
+        ComboParameter lookup(String name);
+    }
+
+    /**
+     * Main routine for replacing holes in a template string. Holes are repeatedly searches, their
+     * corresponding parameters retrieved, and replaced through expansion; since an expansion can
+     * lead to more holes, the process has to be applied until a fixed point is reached.
+     */
+    static String expandTemplate(String template, Resolver resolver) {
+        CharSequence in = template;
+        StringBuffer out = new StringBuffer();
+        while (true) {
+            boolean more = false;
+            Matcher m = pattern.matcher(in);
+            while (m.find()) {
+                String parameterName = m.group(1);
+                String minor = m.group(2);
+                ComboParameter parameter = resolver.lookup(parameterName);
+                if (parameter == null) {
+                    throw new IllegalStateException("Unhandled parameter name " + parameterName);
+                }
+
+                String replacement = parameter.expand(minor);
+                more |= pattern.matcher(replacement).find();
+                m.appendReplacement(out, replacement);
+            }
+            m.appendTail(out);
+            if (!more)
+                return out.toString();
+            else {
+                in = out;
+                out = new StringBuffer();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lib/combo/ComboTask.java	Mon Aug 31 17:33:34 2015 +0100
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package combo;
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TaskEvent.Kind;
+import com.sun.source.util.TaskListener;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.util.List;
+import combo.ComboParameter.Resolver;
+
+import javax.lang.model.element.Element;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import java.io.IOException;
+import java.io.Writer;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+/**
+ * This class represents a compilation task associated with a combo test instance. This is a small
+ * wrapper around {@link JavacTask} which allows for fluent setup style and which makes use of
+ * the shared compilation context to speedup performances.
+ */
+public class ComboTask {
+
+    /** Sources to be compiled in this task. */
+    private List<JavaFileObject> sources = List.nil();
+
+    /** Options associated with this task. */
+    private List<String> options = List.nil();
+
+    /** Diagnostic collector. */
+    private DiagnosticCollector diagsCollector = new DiagnosticCollector();
+
+    /** Output writer. */
+    private Writer out;
+
+    /** Listeners associated with this task. */
+    private List<TaskListener> listeners = List.nil();
+
+    /** Underlying javac task object. */
+    private JavacTask task;
+
+    /** Combo execution environment. */
+    private ComboTestHelper<?>.Env env;
+
+    ComboTask(ComboTestHelper<?>.Env env) {
+        this.env = env;
+    }
+
+    /**
+     * Add a new source to this task.
+     */
+    public ComboTask withSource(JavaFileObject comboSource) {
+        sources = sources.prepend(comboSource);
+        return this;
+    }
+
+    /**
+     * Add a new template source with given name to this task; the template is replaced with
+     * corresponding combo parameters (as defined in the combo test environment).
+     */
+    public ComboTask withSourceFromTemplate(String name, String template) {
+        return withSource(new ComboTemplateSource(name, template));
+    }
+
+    /**
+     * Add a new template source with default name ("Test") to this task; the template is replaced with
+     * corresponding combo parameters (as defined in the combo test environment).
+     */
+    public ComboTask withSourceFromTemplate(String template) {
+        return withSource(new ComboTemplateSource("Test", template));
+    }
+
+    /**
+     * Add a new template source with given name to this task; the template is replaced with
+     * corresponding combo parameters (as defined in the combo test environment). A custom resolver
+     * is used to add combo parameter mappings to the current combo test environment.
+     */
+    public ComboTask withSourceFromTemplate(String name, String template, Resolver resolver) {
+        return withSource(new ComboTemplateSource(name, template, resolver));
+    }
+
+    /**
+     * Add a new template source with default name ("Test") to this task; the template is replaced with
+     * corresponding combo parameters (as defined in the combo test environment). A custom resolver
+     * is used to add combo parameter mappings to the current combo test environment.
+     */
+    public ComboTask withSourceFromTemplate(String template, Resolver resolver) {
+        return withSource(new ComboTemplateSource("Test", template, resolver));
+    }
+
+    /**
+     * Add a new option to this task.
+     */
+    public ComboTask withOption(String opt) {
+        options = options.append(opt);
+        return this;
+    }
+
+    /**
+     * Add a set of options to this task.
+     */
+    public ComboTask withOptions(String[] opts) {
+        for (String opt : opts) {
+            options = options.append(opt);
+        }
+        return this;
+    }
+
+    /**
+     * Add a set of options to this task.
+     */
+    public ComboTask withOptions(Iterable<? extends String> opts) {
+        for (String opt : opts) {
+            options = options.append(opt);
+        }
+        return this;
+    }
+
+    /**
+     * Set the output writer associated with this task.
+     */
+    public ComboTask withWriter(Writer out) {
+        this.out = out;
+        return this;
+    }
+
+    /**
+     * Add a task listener to this task.
+     */
+    public ComboTask withListener(TaskListener listener) {
+        listeners = listeners.prepend(listener);
+        return this;
+    }
+
+    /**
+     * Parse the sources associated with this task.
+     */
+    public Result<Iterable<? extends CompilationUnitTree>> parse() throws IOException {
+        return new Result<>(getTask().parse());
+    }
+
+    /**
+     * Parse and analyzes the sources associated with this task.
+     */
+    public Result<Iterable<? extends Element>> analyze() throws IOException {
+        return new Result<>(getTask().analyze());
+    }
+
+    /**
+     * Parse, analyze and perform code generation for the sources associated with this task.
+     */
+    public Result<Iterable<? extends JavaFileObject>> generate() throws IOException {
+        return new Result<>(getTask().generate());
+    }
+
+    /**
+     * Fork a new compilation task; if possible the compilation context from previous executions is
+     * retained (see comments in ReusableContext as to when it's safe to do so); otherwise a brand
+     * new context is created.
+     */
+    public JavacTask getTask() {
+        if (task == null) {
+            ReusableContext context = env.context();
+            String opts = options == null ? "" :
+                    StreamSupport.stream(options.spliterator(), false).collect(Collectors.joining());
+            context.clear();
+            if (!context.polluted && (context.opts == null || context.opts.equals(opts))) {
+                //we can reuse former context
+                env.info().ctxReusedCount++;
+            } else {
+                env.info().ctxDroppedCount++;
+                //it's not safe to reuse context - create a new one
+                context = env.setContext(new ReusableContext());
+            }
+            context.opts = opts;
+            JavacTask javacTask = ((JavacTool)env.javaCompiler()).getTask(out, env.fileManager(),
+                    diagsCollector, options, null, sources, context);
+            javacTask.setTaskListener(context);
+            for (TaskListener l : listeners) {
+                javacTask.addTaskListener(l);
+            }
+            task = javacTask;
+        }
+        return task;
+    }
+
+    /**
+     * This class is used to help clients accessing the results of a given compilation task.
+     * Contains several helper methods to inspect diagnostics generated during the task execution.
+     */
+    public class Result<D> {
+
+        /** The underlying compilation results. */
+        private final D data;
+
+        public Result(D data) {
+            this.data = data;
+        }
+
+        public D get() {
+            return data;
+        }
+
+        /**
+         * Did this task generate any error diagnostics?
+         */
+        public boolean hasErrors() {
+            return diagsCollector.diagsByKind.containsKey(Diagnostic.Kind.ERROR);
+        }
+
+        /**
+         * Did this task generate any warning diagnostics?
+         */
+        public boolean hasWarnings() {
+            return diagsCollector.diagsByKind.containsKey(Diagnostic.Kind.WARNING);
+        }
+
+        /**
+         * Did this task generate any note diagnostics?
+         */
+        public boolean hasNotes() {
+            return diagsCollector.diagsByKind.containsKey(Diagnostic.Kind.NOTE);
+        }
+
+        /**
+         * Did this task generate any diagnostic with given key?
+         */
+        public boolean containsKey(String key) {
+            return diagsCollector.diagsByKeys.containsKey(key);
+        }
+
+        /**
+         * Retrieve the list of diagnostics of a given kind.
+         */
+        public List<Diagnostic<? extends JavaFileObject>> diagnosticsForKind(Diagnostic.Kind kind) {
+            List<Diagnostic<? extends JavaFileObject>> diags = diagsCollector.diagsByKind.get(kind);
+            return diags != null ? diags : List.nil();
+        }
+
+        /**
+         * Retrieve the list of diagnostics with given key.
+         */
+        public List<Diagnostic<? extends JavaFileObject>> diagnosticsForKey(String key) {
+            List<Diagnostic<? extends JavaFileObject>> diags = diagsCollector.diagsByKeys.get(key);
+            return diags != null ? diags : List.nil();
+        }
+
+        /**
+         * Dump useful info associated with this task.
+         */
+        public String compilationInfo() {
+            return "instance#" + env.info().comboCount + ":[ options = " + options
+                    + ", diagnostics = " + diagsCollector.diagsByKeys.keySet()
+                    + ", dimensions = " + env.bindings
+                    + ", sources = \n" + sources.stream().map(s -> {
+                try {
+                    return s.getCharContent(true);
+                } catch (IOException ex) {
+                    return "";
+                }
+            }).collect(Collectors.joining(",")) + "]";
+        }
+    }
+
+    /**
+     * This class represents a Java source file whose contents are defined in terms of a template
+     * string. The holes in such template are expanded using corresponding combo parameter
+     * instances which can be retrieved using a resolver object.
+     */
+    class ComboTemplateSource extends SimpleJavaFileObject {
+
+        String source;
+        Map<String, ComboParameter> localParametersCache = new HashMap<>();
+
+        protected ComboTemplateSource(String name, String template) {
+            this(name, template, null);
+        }
+
+        protected ComboTemplateSource(String name, String template, Resolver resolver) {
+            super(URI.create("myfo:/" + env.info().comboCount + "/" + name + ".java"), Kind.SOURCE);
+            source = ComboParameter.expandTemplate(template, pname -> resolveParameter(pname, resolver));
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+
+        /**
+         * Combo parameter resolver function. First parameters are looked up in the global environment,
+         * then the local environment is looked up as a fallback.
+         */
+        ComboParameter resolveParameter(String pname, Resolver resolver) {
+            //first search the env
+            ComboParameter parameter = env.parametersCache.get(pname);
+            if (parameter == null) {
+                //then lookup local cache
+                parameter = localParametersCache.get(pname);
+                if (parameter == null && resolver != null) {
+                    //if still null and we have a custom resolution function, try that
+                    parameter = resolver.lookup(pname);
+                    if (parameter != null) {
+                       //if a match was found, store it in the local cache to aviod redundant recomputation
+                       localParametersCache.put(pname, parameter);
+                    }
+                }
+            }
+            return parameter;
+        }
+    }
+
+    /**
+     * Helper class to collect all diagnostic generated during the execution of a given compilation task.
+     */
+    class DiagnosticCollector implements DiagnosticListener<JavaFileObject> {
+
+        Map<Diagnostic.Kind, List<Diagnostic<? extends JavaFileObject>>> diagsByKind = new HashMap<>();
+        Map<String, List<Diagnostic<? extends JavaFileObject>>> diagsByKeys = new HashMap<>();
+
+        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+            List<Diagnostic<? extends JavaFileObject>> diags =
+                    diagsByKeys.getOrDefault(diagnostic.getCode(), List.nil());
+            diagsByKeys.put(diagnostic.getCode(), diags.prepend(diagnostic));
+            Diagnostic.Kind kind = diagnostic.getKind();
+            diags = diagsByKind.getOrDefault(kind, List.nil());
+            diagsByKind.put(kind, diags.prepend(diagnostic));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lib/combo/ComboTestHelper.java	Mon Aug 31 17:33:34 2015 +0100
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package combo;
+
+import javax.tools.JavaCompiler;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Stack;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+
+/**
+ * An helper class for defining combinatorial (aka "combo" tests). A combo test is made up of one
+ * or more 'dimensions' - each of which represent a different axis of the test space. For instance,
+ * if we wanted to test class/interface declaration, one dimension could be the keyword used for
+ * the declaration (i.e. 'class' vs. 'interface') while another dimension could be the class/interface
+ * modifiers (i.e. 'public', 'pachake-private' etc.). A combo test consists in running a test instance
+ * for each point in the test space; that is, for any combination of the combo test dimension:
+ * <p>
+ * 'public' 'class'
+ * 'public' interface'
+ * 'package-private' 'class'
+ * 'package-private' 'interface'
+ * ...
+ * <p>
+ * A new test instance {@link ComboInstance} is created, and executed, after its dimensions have been
+ * initialized accordingly. Each instance can either pass, fail or throw an unexpected error; this helper
+ * class defines several policies for how failures should be handled during a combo test execution
+ * (i.e. should errors be ignored? Do we want the first failure to result in a failure of the whole
+ * combo test?).
+ * <p>
+ * Additionally, this helper class allows to specify filter methods that can be used to throw out
+ * illegal combinations of dimensions - for instance, in the example above, we might want to exclude
+ * all combinations involving 'protected' and 'private' modifiers, which are disallowed for toplevel
+ * declarations.
+ * <p>
+ * While combo tests can be used for a variety of workloads, typically their main task will consist
+ * in performing some kind of javac compilation. For this purpose, this framework defines an optimized
+ * javac context {@link ReusableContext} which can be shared across multiple combo instances,
+ * when the framework detects it's safe to do so. This allows to reduce the overhead associated with
+ * compiler initialization when the test space is big.
+ */
+public class ComboTestHelper<X extends ComboInstance<X>> {
+
+    /** Failure mode. */
+    FailMode failMode = FailMode.FAIL_FAST;
+
+    /** Ignore mode. */
+    IgnoreMode ignoreMode = IgnoreMode.IGNORE_NONE;
+
+    /** Combo test instance filter. */
+    Optional<Predicate<X>> optFilter = Optional.empty();
+
+    /** Combo test dimensions. */
+    List<DimensionInfo<?>> dimensionInfos = new ArrayList<>();
+
+    /** Combo test stats. */
+    Info info = new Info();
+
+    /** Shared JavaCompiler used across all combo test instances. */
+    JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+
+    /** Shared file manager used across all combo test instances. */
+    StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+    /** Shared context used across all combo instances. */
+    ReusableContext context = new ReusableContext();
+
+    /**
+     * Set failure mode for this combo test.
+     */
+    public ComboTestHelper<X> withFailMode(FailMode failMode) {
+        this.failMode = failMode;
+        return this;
+    }
+
+    /**
+     * Set ignore mode for this combo test.
+     */
+    public ComboTestHelper<X> withIgnoreMode(IgnoreMode ignoreMode) {
+        this.ignoreMode = ignoreMode;
+        return this;
+    }
+
+    /**
+     * Set a filter for combo test instances to be ignored.
+     */
+    public ComboTestHelper<X> withFilter(Predicate<X> filter) {
+        optFilter = Optional.of(optFilter.map(filter::and).orElse(filter));
+        return this;
+    }
+
+    /**
+     * Adds a new dimension to this combo test, with a given name an array of values.
+     */
+    @SafeVarargs
+    public final <D> ComboTestHelper<X> withDimension(String name, D... dims) {
+        return withDimension(name, null, dims);
+    }
+
+    /**
+     * Adds a new dimension to this combo test, with a given name, an array of values and a
+     * coresponding setter to be called in order to set the dimension value on the combo test instance
+     * (before test execution).
+     */
+    @SuppressWarnings("unchecked")
+    @SafeVarargs
+    public final <D> ComboTestHelper<X> withDimension(String name, DimensionSetter<X, D> setter, D... dims) {
+        dimensionInfos.add(new DimensionInfo<>(name, dims, setter));
+        return this;
+    }
+
+    /**
+     * Adds a new array dimension to this combo test, with a given base name. This allows to specify
+     * multiple dimensions at once; the names of the underlying dimensions will be generated from the
+     * base name, using standard array bracket notation - i.e. "DIM[0]", "DIM[1]", etc.
+     */
+    @SafeVarargs
+    public final <D> ComboTestHelper<X> withArrayDimension(String name, int size, D... dims) {
+        return withArrayDimension(name, null, size, dims);
+    }
+
+    /**
+     * Adds a new array dimension to this combo test, with a given base name, an array of values and a
+     * coresponding array setter to be called in order to set the dimension value on the combo test
+     * instance (before test execution). This allows to specify multiple dimensions at once; the names
+     * of the underlying dimensions will be generated from the base name, using standard array bracket
+     * notation - i.e. "DIM[0]", "DIM[1]", etc.
+     */
+    @SafeVarargs
+    public final <D> ComboTestHelper<X> withArrayDimension(String name, ArrayDimensionSetter<X, D> setter, int size, D... dims) {
+        for (int i = 0 ; i < size ; i++) {
+            dimensionInfos.add(new ArrayDimensionInfo<>(name, dims, i, setter));
+        }
+        return this;
+    }
+
+    /**
+     * Returns the stat object associated with this combo test.
+     */
+    public Info info() {
+        return info;
+    }
+
+    /**
+     * Runs this combo test. This will generate the combinatorial explosion of all dimensions, and
+     * execute a new test instance (built using given supplier) for each such combination.
+     */
+    public void run(Supplier<X> instanceBuilder) {
+        run(instanceBuilder, null);
+    }
+
+    /**
+     * Runs this combo test. This will generate the combinatorial explosion of all dimensions, and
+     * execute a new test instance (built using given supplier) for each such combination. Before
+     * executing the test instance entry point, the supplied initialization method is called on
+     * the test instance; this is useful for ad-hoc test instance initialization once all the dimension
+     * values have been set.
+     */
+    public void run(Supplier<X> instanceBuilder, Consumer<X> initAction) {
+        runInternal(0, new Stack<>(), instanceBuilder, Optional.ofNullable(initAction));
+        end();
+    }
+
+    /**
+     * Generate combinatorial explosion of all dimension values and create a new test instance
+     * for each combination.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private void runInternal(int index, Stack<DimensionBinding<?>> bindings, Supplier<X> instanceBuilder, Optional<Consumer<X>> initAction) {
+        if (index == dimensionInfos.size()) {
+            runCombo(instanceBuilder, initAction, bindings);
+        } else {
+            DimensionInfo<?> dinfo = dimensionInfos.get(index);
+            for (Object d : dinfo.dims) {
+                bindings.push(new DimensionBinding(d, dinfo));
+                runInternal(index + 1, bindings, instanceBuilder, initAction);
+                bindings.pop();
+            }
+        }
+    }
+
+    /**
+     * Run a new test instance using supplied dimension bindings. All required setters and initialization
+     * method are executed before calling the instance main entry point. Also checks if the instance
+     * is compatible with the specified test filters; if not, the test is simply skipped.
+     */
+    @SuppressWarnings("unchecked")
+    private void runCombo(Supplier<X> instanceBuilder, Optional<Consumer<X>> initAction, List<DimensionBinding<?>> bindings) {
+        X x = instanceBuilder.get();
+        for (DimensionBinding<?> binding : bindings) {
+            binding.init(x);
+        }
+        initAction.ifPresent(action -> action.accept(x));
+        info.comboCount++;
+        if (!optFilter.isPresent() || optFilter.get().test(x)) {
+            x.run(new Env(bindings));
+            if (failMode.shouldStop(ignoreMode, info)) {
+                end();
+            }
+        } else {
+            info.skippedCount++;
+        }
+    }
+
+    /**
+     * This method is executed upon combo test completion (either normal or erroneous). Closes down
+     * all pending resources and dumps useful stats info.
+     */
+    private void end() {
+        try {
+            fm.close();
+            if (info.hasFailures()) {
+                throw new AssertionError("Failure when executing combo:" + info.lastFailure.orElse(""));
+            } else if (info.hasErrors()) {
+                throw new AssertionError("Unexpected exception while executing combo", info.lastError.get());
+            }
+        } catch (IOException ex) {
+            throw new AssertionError("Failure when closing down shared file manager; ", ex);
+        } finally {
+            info.dump();
+        }
+    }
+
+    /**
+     * Functional interface for specifying combo test instance setters.
+     */
+    public interface DimensionSetter<X extends ComboInstance<X>, D> {
+        void set(X x, D d);
+    }
+
+    /**
+     * Functional interface for specifying combo test instance array setters. The setter method
+     * receives an extra argument for the index of the array element to be set.
+     */
+    public interface ArrayDimensionSetter<X extends ComboInstance<X>, D> {
+        void set(X x, D d, int index);
+    }
+
+    /**
+     * Dimension descriptor; each dimension has a name, an array of value and an optional setter
+     * to be called on the associated combo test instance.
+     */
+    class DimensionInfo<D> {
+        String name;
+        D[] dims;
+        boolean isParameter;
+        Optional<DimensionSetter<X, D>> optSetter;
+
+        DimensionInfo(String name, D[] dims, DimensionSetter<X, D> setter) {
+            this.name = name;
+            this.dims = dims;
+            this.optSetter = Optional.ofNullable(setter);
+            this.isParameter = dims[0] instanceof ComboParameter;
+        }
+    }
+
+    /**
+     * Array dimension descriptor. The dimension name is derived from a base name and an index using
+     * standard bracket notation; ; the setter accepts an additional 'index' argument to point
+     * to the array element to be initialized.
+     */
+    class ArrayDimensionInfo<D> extends DimensionInfo<D> {
+        public ArrayDimensionInfo(String name, D[] dims, int index, ArrayDimensionSetter<X, D> setter) {
+            super(String.format("%s[%d]", name, index), dims,
+                    setter != null ? (x, d) -> setter.set(x, d, index) : null);
+        }
+    }
+
+    /**
+     * Failure policies for a combo test run.
+     */
+    public enum FailMode {
+        /** Combo test fails when first failure is detected. */
+        FAIL_FAST,
+        /** Combo test fails after all instances have been executed. */
+        FAIL_AFTER;
+
+        boolean shouldStop(IgnoreMode ignoreMode, Info info) {
+            switch (this) {
+                case FAIL_FAST:
+                    return !ignoreMode.canIgnore(info);
+                default:
+                    return false;
+            }
+        }
+    }
+
+    /**
+     * Ignore policies for a combo test run.
+     */
+    public enum IgnoreMode {
+        /** No error or failure is ignored. */
+        IGNORE_NONE,
+        /** Only errors are ignored. */
+        IGNORE_ERRORS,
+        /** Only failures are ignored. */
+        IGNORE_FAILURES,
+        /** Both errors and failures are ignored. */
+        IGNORE_ALL;
+
+        boolean canIgnore(Info info) {
+            switch (this) {
+                case IGNORE_ERRORS:
+                    return info.failCount == 0;
+                case IGNORE_FAILURES:
+                    return info.errCount == 0;
+                case IGNORE_ALL:
+                    return true;
+                default:
+                    return info.failCount == 0 && info.errCount == 0;
+            }
+        }
+    }
+
+    /**
+     * A dimension binding. This is essentially a pair of a dimension value and its corresponding
+     * dimension info.
+     */
+    class DimensionBinding<D> {
+        D d;
+        DimensionInfo<D> info;
+
+        DimensionBinding(D d, DimensionInfo<D> info) {
+            this.d = d;
+            this.info = info;
+        }
+
+        void init(X x) {
+            info.optSetter.ifPresent(setter -> setter.set(x, d));
+        }
+
+        public String toString() {
+            return String.format("(%s -> %s)", info.name, d);
+        }
+    }
+
+    /**
+     * This class is used to keep track of combo tests stats; info such as numbero of failures/errors,
+     * number of times a context has been shared/dropped are all recorder here.
+     */
+    public static class Info {
+        int failCount;
+        int errCount;
+        int passCount;
+        int comboCount;
+        int skippedCount;
+        int ctxReusedCount;
+        int ctxDroppedCount;
+        Optional<String> lastFailure = Optional.empty();
+        Optional<Throwable> lastError = Optional.empty();
+
+        void dump() {
+            System.err.println(String.format("%d total checks executed", comboCount));
+            System.err.println(String.format("%d successes found", passCount));
+            System.err.println(String.format("%d failures found", failCount));
+            System.err.println(String.format("%d errors found", errCount));
+            System.err.println(String.format("%d skips found", skippedCount));
+            System.err.println(String.format("%d contexts shared", ctxReusedCount));
+            System.err.println(String.format("%d contexts dropped", ctxDroppedCount));
+        }
+
+        public boolean hasFailures() {
+            return failCount != 0;
+        }
+
+        public boolean hasErrors() {
+            return errCount != 0;
+        }
+    }
+
+    /**
+     * THe execution environment for a given combo test instance. An environment contains the
+     * bindings for all the dimensions, along with the combo parameter cache (this is non-empty
+     * only if one or more dimensions are subclasses of the {@code ComboParameter} interface).
+     */
+    class Env {
+        List<DimensionBinding<?>> bindings;
+        Map<String, ComboParameter> parametersCache = new HashMap<>();
+
+        @SuppressWarnings({"Unchecked", "rawtypes"})
+        Env(List<DimensionBinding<?>> bindings) {
+            this.bindings = bindings;
+            for (DimensionBinding<?> binding : bindings) {
+                if (binding.info.isParameter) {
+                    parametersCache.put(binding.info.name, (ComboParameter)binding.d);
+                };
+            }
+        }
+
+        Info info() {
+            return ComboTestHelper.this.info();
+        }
+
+        StandardJavaFileManager fileManager() {
+            return fm;
+        }
+
+        JavaCompiler javaCompiler() {
+            return comp;
+        }
+
+        ReusableContext context() {
+            return context;
+        }
+
+        ReusableContext setContext(ReusableContext context) {
+            return ComboTestHelper.this.context = context;
+        }
+    }
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lib/combo/ReusableContext.java	Mon Aug 31 17:33:34 2015 +0100
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package combo;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskEvent.Kind;
+import com.sun.source.util.TaskListener;
+import com.sun.source.util.TreeScanner;
+import com.sun.tools.javac.api.MultiTaskListener;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.Check;
+import com.sun.tools.javac.comp.CompileStates;
+import com.sun.tools.javac.comp.Enter;
+import com.sun.tools.javac.main.Arguments;
+import com.sun.tools.javac.main.JavaCompiler;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Log;
+
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A reusable context is a context that can be used safely across multiple compilation rounds
+ * arising from execution of a combo test. It achieves reuse by replacing some components
+ * (most notably JavaCompiler and Log) with reusable counterparts, and by exposing a method
+ * to cleanup leftovers from previous compilation.
+ * <p>
+ * There are, however, situations in which reusing the context is not safe: (i) when different
+ * compilations are using different sets of compiler options (as most option values are cached
+ * inside components themselves) and (ii) when the compilation unit happens to redefine classes
+ * in the java.* packages.
+ */
+class ReusableContext extends Context implements TaskListener {
+
+    Set<CompilationUnitTree> roots = new HashSet<>();
+
+    String opts;
+    boolean polluted = false;
+
+    ReusableContext() {
+        super();
+        put(Log.logKey, ReusableLog.factory);
+        put(JavaCompiler.compilerKey, ReusableJavaCompiler.factory);
+    }
+
+    void clear() {
+        drop(Arguments.argsKey);
+        drop(DiagnosticListener.class);
+        drop(Log.outKey);
+        drop(JavaFileManager.class);
+        drop(JavacTask.class);
+
+        if (ht.get(Log.logKey) instanceof ReusableLog) {
+            //log already inited - not first round
+            ((ReusableLog)Log.instance(this)).clear();
+            Enter.instance(this).newRound();
+            ((ReusableJavaCompiler)ReusableJavaCompiler.instance(this)).clear();
+            Types.instance(this).newRound();
+            Check.instance(this).newRound();
+            CompileStates.instance(this).clear();
+            MultiTaskListener.instance(this).clear();
+
+            //find if any of the roots have redefined java.* classes
+            Symtab syms = Symtab.instance(this);
+            new TreeScanner<Void, Void>() {
+                @Override
+                public Void visitClass(ClassTree node, Void aVoid) {
+                    Symbol sym = ((JCClassDecl)node).sym;
+                    if (sym != null) {
+                        syms.classes.remove(sym.flatName());
+                        if (sym.flatName().toString().startsWith("java.")) {
+                            polluted = true;
+                        }
+                    }
+                    return super.visitClass(node, aVoid);
+                }
+            }.scan(roots, null);
+            roots.clear();
+        }
+    }
+
+    @Override
+    public void finished(TaskEvent e) {
+        if (e.getKind() == Kind.PARSE) {
+            roots.add(e.getCompilationUnit());
+        }
+    }
+
+    @Override
+    public void started(TaskEvent e) {
+        //do nothing
+    }
+
+    <T> void drop(Key<T> k) {
+        ht.remove(k);
+    }
+
+    <T> void drop(Class<T> c) {
+        ht.remove(key(c));
+    }
+
+    /**
+     * Reusable JavaCompiler; exposes a method to clean up the component from leftovers associated with
+     * previous compilations.
+     */
+    static class ReusableJavaCompiler extends JavaCompiler {
+
+        static Factory<JavaCompiler> factory = ReusableJavaCompiler::new;
+
+        ReusableJavaCompiler(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void close() {
+            //do nothing
+        }
+
+        void clear() {
+            newRound();
+        }
+
+        @Override
+        protected void checkReusable() {
+            //do nothing - it's ok to reuse the compiler
+        }
+    }
+
+    /**
+     * Reusable Log; exposes a method to clean up the component from leftovers associated with
+     * previous compilations.
+     */
+    static class ReusableLog extends Log {
+
+        static Factory<Log> factory = ReusableLog::new;
+
+        Context context;
+
+        ReusableLog(Context context) {
+            super(context);
+            this.context = context;
+        }
+
+        void clear() {
+            recorded.clear();
+            sourceMap.clear();
+            nerrors = 0;
+            nwarnings = 0;
+            //Set a fake listener that will lazily lookup the context for the 'real' listener. Since
+            //this field is never updated when a new task is created, we cannot simply reset the field
+            //or keep old value. This is a hack to workaround the limitations in the current infrastructure.
+            diagListener = new DiagnosticListener<JavaFileObject>() {
+                DiagnosticListener<JavaFileObject> cachedListener;
+
+                @Override
+                @SuppressWarnings("unchecked")
+                public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+                    if (cachedListener == null) {
+                        cachedListener = context.get(DiagnosticListener.class);
+                    }
+                    cachedListener.report(diagnostic);
+                }
+            };
+        }
+    }
+}
--- a/langtools/test/tools/javac/multicatch/7030606/DisjunctiveTypeWellFormednessTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/multicatch/7030606/DisjunctiveTypeWellFormednessTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,30 +23,31 @@
 
 /*
  * @test
- * @bug 7030606 8006694
+ * @bug 7030606 8006694 8129962
  * @summary Project-coin: multi-catch types should be pairwise disjoint
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm DisjunctiveTypeWellFormednessTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main DisjunctiveTypeWellFormednessTest
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
 
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-public class DisjunctiveTypeWellFormednessTest
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
 
-    enum Alternative {
+public class DisjunctiveTypeWellFormednessTest extends ComboInstance<DisjunctiveTypeWellFormednessTest> {
+
+    enum Alternative implements ComboParameter {
         EXCEPTION("Exception"),
         RUNTIME_EXCEPTION("RuntimeException"),
         IO_EXCEPTION("java.io.IOException"),
@@ -55,21 +56,10 @@
 
         String exceptionStr;
 
-        private Alternative(String exceptionStr) {
+        Alternative(String exceptionStr) {
             this.exceptionStr = exceptionStr;
         }
 
-        static String makeDisjunctiveType(Alternative... alternatives) {
-            StringBuilder buf = new StringBuilder();
-            String sep = "";
-            for (Alternative alternative : alternatives) {
-                buf.append(sep);
-                buf.append(alternative.exceptionStr);
-                sep = "|";
-            }
-            return buf.toString();
-        }
-
         boolean disjoint(Alternative that) {
             return disjoint[this.ordinal()][that.ordinal()];
         }
@@ -82,135 +72,85 @@
             /*FileNotFoundException*/    {  false,       true,               false,         false,                   true },
             /*IllegalArgumentException*/ {  false,       false,              true,          true,                    false }
         };
+
+        @Override
+        public String expand(String optParameter) {
+            return exceptionStr;
+        }
     }
 
-    enum Arity {
-        ONE(1),
-        TWO(2),
-        THREE(3),
-        FOUR(4),
-        FIVE(5);
+    enum Arity implements ComboParameter {
+        ONE(1, "#{TYPE[0]}"),
+        TWO(2, "#{TYPE[0]} | #{TYPE[1]}"),
+        THREE(3, "#{TYPE[0]} | #{TYPE[1]} | #{TYPE[2]}"),
+        FOUR(4, "#{TYPE[0]} | #{TYPE[1]} | #{TYPE[2]} | #{TYPE[3]}"),
+        FIVE(5, "#{TYPE[0]} | #{TYPE[1]} | #{TYPE[2]} | #{TYPE[3]} | #{TYPE[4]}");
 
         int n;
+        String arityTemplate;
 
-        private Arity(int n) {
+        Arity(int n, String arityTemplate) {
             this.n = n;
+            this.arityTemplate = arityTemplate;
+        }
+
+        @Override
+        public String expand(String optParameter) {
+            return arityTemplate;
         }
     }
 
     public static void main(String... args) throws Exception {
-        for (Arity arity : Arity.values()) {
-            for (Alternative a1 : Alternative.values()) {
-                if (arity == Arity.ONE) {
-                    pool.execute(new DisjunctiveTypeWellFormednessTest(a1));
-                    continue;
-                }
-                for (Alternative a2 : Alternative.values()) {
-                    if (arity == Arity.TWO) {
-                        pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2));
-                        continue;
-                    }
-                    for (Alternative a3 : Alternative.values()) {
-                        if (arity == Arity.THREE) {
-                            pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2, a3));
-                            continue;
-                        }
-                        for (Alternative a4 : Alternative.values()) {
-                            if (arity == Arity.FOUR) {
-                                pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2, a3, a4));
-                                continue;
-                            }
-                            for (Alternative a5 : Alternative.values()) {
-                                pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2, a3, a4, a5));
-                            }
-                        }
-                    }
+        new ComboTestHelper<DisjunctiveTypeWellFormednessTest>()
+                .withFilter(DisjunctiveTypeWellFormednessTest::arityFilter)
+                .withDimension("CTYPE", (x, arity) -> x.arity = arity, Arity.values())
+                .withArrayDimension("TYPE", (x, type, idx) -> x.alternatives[idx] = type, 5, Alternative.values())
+                .run(DisjunctiveTypeWellFormednessTest::new);
+    }
+
+    Arity arity;
+    Alternative[] alternatives = new Alternative[5];
+
+    boolean arityFilter() {
+        for (int i = arity.n; i < alternatives.length ; i++) {
+            if (alternatives[i].ordinal() != 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    String template = "class Test {\n" +
+                      "void test() {\n" +
+                      "try {} catch (#{CTYPE} e) {}\n" +
+                      "}\n" +
+                      "}\n";
+
+    @Override
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withSourceFromTemplate(template)
+                .analyze());
+    }
+
+    void check(Result<?> res) {
+
+        int non_disjoint = 0;
+        for (int i = 0 ; i < arity.n ; i++) {
+            for (int j = 0 ; j < i ; j++) {
+                if (!alternatives[i].disjoint(alternatives[j])) {
+                    non_disjoint++;
+                    break;
                 }
             }
         }
 
-        checkAfterExec(false);
-    }
-
-    Alternative[] alternatives;
-    JavaSource source;
-    DiagnosticChecker diagChecker;
-
-    DisjunctiveTypeWellFormednessTest(Alternative... alternatives) {
-        this.alternatives = alternatives;
-        this.source = new JavaSource();
-        this.diagChecker = new DiagnosticChecker();
-    }
-
-    class JavaSource extends SimpleJavaFileObject {
-
-        String template = "class Test {\n" +
-                              "void test() {\n" +
-                                 "try {} catch (#T e) {}\n" +
-                              "}\n" +
-                          "}\n";
-
-        String source;
-
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = template.replace("#T", Alternative.makeDisjunctiveType(alternatives));
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
+        int foundErrs = res.diagnosticsForKey("compiler.err.multicatch.types.must.be.disjoint").size();
+        if (non_disjoint != foundErrs) {
+            fail("invalid diagnostics for source:\n" +
+                    res.compilationInfo() +
+                    "\nFound errors: " + foundErrs +
+                    "\nExpected errors: " + non_disjoint);
         }
     }
-
-    @Override
-    public void run() {
-        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
-                null, null, Arrays.asList(source));
-        try {
-            ct.analyze();
-        } catch (Throwable t) {
-            processException(t);
-            return;
-        }
-        check();
-    }
-
-    void check() {
-
-        int non_disjoint = 0;
-        int i = 0;
-        for (Alternative a1 : alternatives) {
-            int j = 0;
-            for (Alternative a2 : alternatives) {
-                if (i == j) continue;
-                if (!a1.disjoint(a2)) {
-                    non_disjoint++;
-                    break;
-                }
-                j++;
-            }
-            i++;
-        }
-
-        if (non_disjoint != diagChecker.errorsFound) {
-            throw new Error("invalid diagnostics for source:\n" +
-                source.getCharContent(true) +
-                "\nFound errors: " + diagChecker.errorsFound +
-                "\nExpected errors: " + non_disjoint);
-        }
-    }
-
-    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        int errorsFound;
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
-                    diagnostic.getCode().startsWith("compiler.err.multicatch.types.must.be.disjoint")) {
-                errorsFound++;
-            }
-        }
-    }
-
 }
--- a/langtools/test/tools/javac/resolve/BitWiseOperators.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/resolve/BitWiseOperators.java	Mon Aug 31 17:33:34 2015 +0100
@@ -21,47 +21,30 @@
  * questions.
  */
 
-/**@test
- * @bug 8082311
+/*
+ * @test
+ * @bug 8082311 8129962
  * @summary Verify that bitwise operators don't allow to mix numeric and boolean operands.
  * @library ../lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main BitWiseOperators
  */
 
 import com.sun.tools.javac.util.StringUtils;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.List;
-import javax.tools.DiagnosticCollector;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
 
-public class BitWiseOperators extends JavacTestingAbstractThreadedTest {
-    public static void main(String... args) {
-        new BitWiseOperators().run();
-    }
+import java.io.IOException;
 
-    void run() {
-        for (TYPE type1 : TYPE.values()) {
-            for (OPERATION op : OPERATION.values()) {
-                for (TYPE type2 : TYPE.values()) {
-                    runTest(type1, op, type2);
-                }
-            }
-        }
-    }
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-    void runTest(TYPE type1, OPERATION op, TYPE type2) {
-        DiagnosticCollector<JavaFileObject> dc = new DiagnosticCollector<>();
-        List<JavaSource> files = Arrays.asList(new JavaSource(type1, op, type2));
-        comp.getTask(null, null, dc, null, null, files).call();
-        if (dc.getDiagnostics().isEmpty() ^ TYPE.compatible(type1, type2)) {
-            throw new AssertionError("Unexpected behavior. Type1: " + type1 +
-                                                        "; type2: " + type2 +
-                                                        "; diagnostics: " + dc.getDiagnostics());
-        }
-    }
 
-    enum TYPE {
+public class BitWiseOperators extends ComboInstance<BitWiseOperators> {
+
+    enum OperandType implements ComboParameter {
         BYTE,
         CHAR,
         SHORT,
@@ -69,45 +52,57 @@
         LONG,
         BOOLEAN;
 
-        public static boolean compatible(TYPE op1, TYPE op2) {
+        public static boolean compatible(OperandType op1, OperandType op2) {
             return !(op1 == BOOLEAN ^ op2 == BOOLEAN);
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return StringUtils.toLowerCase(name());
+        }
     }
 
-    enum OPERATION {
+    enum OperatorKind implements ComboParameter {
         BITAND("&"),
         BITOR("|"),
         BITXOR("^");
 
         String op;
 
-        private OPERATION(String op) {
+        OperatorKind(String op) {
             this.op = op;
         }
 
-    }
-
-    class JavaSource extends SimpleJavaFileObject {
-
-        String template = "class Test {\n" +
-                          "    public Object test(#TYPE1 var1, #TYPE2 var2) {\n" +
-                          "        return var1 #OP var2;\n" +
-                          "    }\n" +
-                          "}";
-
-        String source;
-
-        public JavaSource(TYPE type1, OPERATION op, TYPE type2) {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = template.replaceAll("#TYPE1", StringUtils.toLowerCase(type1.name()))
-                             .replaceAll("#OP", StringUtils.toLowerCase(op.op))
-                             .replaceAll("#TYPE2", StringUtils.toLowerCase(type2.name()));
-        }
-
         @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
+        public String expand(String optParameter) {
+            return op;
         }
     }
 
+    public static void main(String... args) {
+        new ComboTestHelper<BitWiseOperators>()
+                .withArrayDimension("TYPE", (x, type, idx) -> x.opTypes[idx] = type, 2, OperandType.values())
+                .withDimension("OP", OperatorKind.values())
+                .run(BitWiseOperators::new);
+    }
+
+    OperandType[] opTypes = new OperandType[2];
+
+    String template = "class Test {\n" +
+                      "    public Object test(#{TYPE[0]} var1, #{TYPE[1]} var2) {\n" +
+                      "        return var1 #{OP} var2;\n" +
+                      "    }\n" +
+                      "}";
+
+    @Override
+    public void doWork() throws IOException {
+        Result<?> res = newCompilationTask()
+                .withSourceFromTemplate(template)
+                .analyze();
+        if (res.hasErrors() == OperandType.compatible(opTypes[0], opTypes[1])) {
+            fail("Unexpected behavior. Type1: " + opTypes[0] +
+                    "; type2: " + opTypes[1] +
+                    "; " + res.compilationInfo());
+        }
+    }
 }
--- a/langtools/test/tools/javac/types/ScopeListenerTest.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/types/ScopeListenerTest.java	Mon Aug 31 17:33:34 2015 +0100
@@ -29,6 +29,7 @@
  */
 
 import com.sun.tools.javac.code.Scope;
+import com.sun.tools.javac.code.Scope.ScopeListenerList;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symtab;
 import com.sun.tools.javac.code.Types;
@@ -53,20 +54,14 @@
         types.membersClosure(syms.stringType, true);
         types.membersClosure(syms.stringType, false);
 
-        Field listenersField = Scope.class.getDeclaredField("listeners");
-
-        listenersField.setAccessible(true);
-
-        int listenerCount =
-                ((Collection) listenersField.get(syms.stringType.tsym.members())).size();
+        int listenerCount = listenerCount(syms.stringType.tsym.members());
 
         for (int i = 0; i < 100; i++) {
             types.membersClosure(syms.stringType, true);
             types.membersClosure(syms.stringType, false);
         }
 
-        int newListenerCount
-                = ((Collection) listenersField.get(syms.stringType.tsym.members())).size();
+        int newListenerCount = listenerCount(syms.stringType.tsym.members());
 
         if (listenerCount != newListenerCount) {
             throw new AssertionError("Orig listener count: " + listenerCount +
@@ -79,4 +74,12 @@
             ;
     }
 
+    int listenerCount(Scope s) throws ReflectiveOperationException {
+        Field listenersListField = Scope.class.getDeclaredField("listeners");
+        listenersListField.setAccessible(true);
+        Field listenersField = ScopeListenerList.class.getDeclaredField("listeners");
+        listenersField.setAccessible(true);
+        return ((Collection<?>)listenersField.get(listenersListField.get(s))).size();
+    }
+
 }
--- a/langtools/test/tools/javac/varargs/7042566/T7042566.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/varargs/7042566/T7042566.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,31 +23,25 @@
 
 /*
  * @test
- * @bug 7042566 8006694
+ * @bug 7042566 8006694 8129962
  * @summary Unambiguous varargs method calls flagged as ambiguous
  *  temporarily workaround combo tests are causing time out in several platforms
- * @library ../../lib
+ * @library /tools/javac/lib
  * @modules jdk.jdeps/com.sun.tools.classfile
+ *          jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
  *          jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm T7042566
+ * @build combo.ComboTestHelper
+ * @run main T7042566
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
+import java.io.InputStream;
+import javax.tools.JavaFileObject;
 
-import java.io.File;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.Locale;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-
-import com.sun.source.util.JavacTask;
 import com.sun.tools.classfile.Instruction;
 import com.sun.tools.classfile.Attribute;
 import com.sun.tools.classfile.ClassFile;
@@ -56,145 +50,12 @@
 import com.sun.tools.classfile.Method;
 import com.sun.tools.javac.util.List;
 
-public class T7042566
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
-
-    VarargsMethod m1;
-    VarargsMethod m2;
-    TypeConfiguration actuals;
-
-    T7042566(TypeConfiguration m1_conf, TypeConfiguration m2_conf,
-            TypeConfiguration actuals) {
-        this.m1 = new VarargsMethod(m1_conf);
-        this.m2 = new VarargsMethod(m2_conf);
-        this.actuals = actuals;
-    }
-
-    @Override
-    public void run() {
-        int id = checkCount.incrementAndGet();
-        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
-        JavaSource source = new JavaSource(id);
-        ErrorChecker ec = new ErrorChecker();
-        JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), ec,
-                null, null, Arrays.asList(source));
-        ct.call();
-        check(source, ec, id);
-    }
-
-    void check(JavaSource source, ErrorChecker ec, int id) {
-        boolean resolutionError = false;
-        VarargsMethod selectedMethod = null;
-
-        boolean m1_applicable = m1.isApplicable(actuals);
-        boolean m2_applicable = m2.isApplicable(actuals);
-
-        if (!m1_applicable && !m2_applicable) {
-            resolutionError = true;
-        } else if (m1_applicable && m2_applicable) {
-            //most specific
-            boolean m1_moreSpecific = m1.isMoreSpecificThan(m2);
-            boolean m2_moreSpecific = m2.isMoreSpecificThan(m1);
-
-            resolutionError = m1_moreSpecific == m2_moreSpecific;
-            selectedMethod = m1_moreSpecific ? m1 : m2;
-        } else {
-            selectedMethod = m1_applicable ?
-                m1 : m2;
-        }
-
-        if (ec.errorFound != resolutionError) {
-            throw new Error("invalid diagnostics for source:\n" +
-                    source.getCharContent(true) +
-                    "\nExpected resolution error: " + resolutionError +
-                    "\nFound error: " + ec.errorFound +
-                    "\nCompiler diagnostics:\n" + ec.printDiags());
-        } else if (!resolutionError) {
-            verifyBytecode(selectedMethod, source, id);
-        }
-    }
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
 
-    void verifyBytecode(VarargsMethod selected, JavaSource source, int id) {
-        bytecodeCheckCount.incrementAndGet();
-        File compiledTest = new File(String.format("Test%d.class", id));
-        try {
-            ClassFile cf = ClassFile.read(compiledTest);
-            Method testMethod = null;
-            for (Method m : cf.methods) {
-                if (m.getName(cf.constant_pool).equals("test")) {
-                    testMethod = m;
-                    break;
-                }
-            }
-            if (testMethod == null) {
-                throw new Error("Test method not found");
-            }
-            Code_attribute ea =
-                (Code_attribute)testMethod.attributes.get(Attribute.Code);
-            if (testMethod == null) {
-                throw new Error("Code attribute for test() method not found");
-            }
-
-            for (Instruction i : ea.getInstructions()) {
-                if (i.getMnemonic().equals("invokevirtual")) {
-                    int cp_entry = i.getUnsignedShort(1);
-                    CONSTANT_Methodref_info methRef =
-                        (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry);
-                    String type = methRef.getNameAndTypeInfo().getType();
-                    String sig = selected.parameterTypes.bytecodeSigStr;
-                    if (!type.contains(sig)) {
-                        throw new Error("Unexpected type method call: " +
-                                        type + "" +
-                                        "\nfound: " + sig +
-                                        "\n" + source.getCharContent(true));
-                    }
-                    break;
-                }
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-            throw new Error("error reading " + compiledTest +": " + e);
-        }
-    }
-
-    class JavaSource extends SimpleJavaFileObject {
-
-        static final String source_template = "class Test#ID {\n" +
-                "   #V1\n" +
-                "   #V2\n" +
-                "   void test() { m(#E); }\n" +
-                "}";
-
-        String source;
-
-        public JavaSource(int id) {
-            super(URI.create(String.format("myfo:/Test%d.java", id)),
-                    JavaFileObject.Kind.SOURCE);
-            source = source_template.replaceAll("#V1", m1.toString())
-                    .replaceAll("#V2", m2.toString())
-                    .replaceAll("#E", actuals.expressionListStr)
-                    .replaceAll("#ID", String.valueOf(id));
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
-    }
-
-    public static void main(String... args) throws Exception {
-        for (TypeConfiguration tconf1 : TypeConfiguration.values()) {
-            for (TypeConfiguration tconf2 : TypeConfiguration.values()) {
-                for (TypeConfiguration tconf3 : TypeConfiguration.values()) {
-                    pool.execute(new T7042566(tconf1, tconf2, tconf3));
-                }
-            }
-        }
-
-        outWriter.println("Bytecode checks made: " + bytecodeCheckCount.get());
-        checkAfterExec();
-    }
+public class T7042566 extends ComboInstance<T7042566> {
 
     enum TypeKind {
         OBJECT("Object", "(Object)null", "Ljava/lang/Object;"),
@@ -216,7 +77,7 @@
         }
     }
 
-    enum TypeConfiguration {
+    enum TypeConfiguration implements ComboParameter {
         A(TypeKind.OBJECT),
         B(TypeKind.STRING),
         AA(TypeKind.OBJECT, TypeKind.OBJECT),
@@ -237,7 +98,7 @@
         String parameterListStr;
         String bytecodeSigStr;
 
-        private TypeConfiguration(TypeKind... typeKindList) {
+        TypeConfiguration(TypeKind... typeKindList) {
             this.typeKindList = List.from(typeKindList);
             expressionListStr = asExpressionList();
             parameterListStr = asParameterList();
@@ -284,6 +145,11 @@
             }
             return buf.toString();
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return expressionListStr;
+        }
     }
 
     static class VarargsMethod {
@@ -333,31 +199,119 @@
         }
     }
 
-    static class ErrorChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
+    public static void main(String[] args) {
+        new ComboTestHelper<T7042566>()
+                .withArrayDimension("SIG", (x, sig, idx) -> x.methodSignatures[idx] = sig, 2, TypeConfiguration.values())
+                .withDimension("ACTUALS", (x, actuals) -> x.actuals = actuals, TypeConfiguration.values())
+                .run(T7042566::new, T7042566::setup);
+    }
 
-        boolean errorFound;
-        List<String> errDiags = List.nil();
+    VarargsMethod m1;
+    VarargsMethod m2;
+    TypeConfiguration[] methodSignatures = new TypeConfiguration[2];
+    TypeConfiguration actuals;
+
+    void setup() {
+        this.m1 = new VarargsMethod(methodSignatures[0]);
+        this.m2 = new VarargsMethod(methodSignatures[1]);
+    }
 
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errDiags = errDiags
-                        .append(diagnostic.getMessage(Locale.getDefault()));
-                errorFound = true;
-            }
-        }
+    final String source_template = "class Test {\n" +
+                "   #{METH.1}\n" +
+                "   #{METH.2}\n" +
+                "   void test() { m(#{ACTUALS}); }\n" +
+                "}";
 
-        String printDiags() {
-            StringBuilder buf = new StringBuilder();
-            for (String s : errDiags) {
-                buf.append(s);
-                buf.append("\n");
-            }
-            return buf.toString();
+    @Override
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withSourceFromTemplate(source_template, this::getMethodDecl)
+                .generate());
+    }
+
+    ComboParameter getMethodDecl(String parameterName) {
+        switch (parameterName) {
+            case "METH": return optParameter -> {
+                return optParameter.equals("1") ?
+                        m1.toString() : m2.toString();
+            };
+            default:
+                return null;
         }
     }
 
-    //number of bytecode checks made while running combo tests
-    static AtomicInteger bytecodeCheckCount = new AtomicInteger();
+    void check(Result<Iterable<? extends JavaFileObject>> res) {
+        boolean resolutionError = false;
+        VarargsMethod selectedMethod = null;
+
+        boolean m1_applicable = m1.isApplicable(actuals);
+        boolean m2_applicable = m2.isApplicable(actuals);
+
+        if (!m1_applicable && !m2_applicable) {
+            resolutionError = true;
+        } else if (m1_applicable && m2_applicable) {
+            //most specific
+            boolean m1_moreSpecific = m1.isMoreSpecificThan(m2);
+            boolean m2_moreSpecific = m2.isMoreSpecificThan(m1);
+
+            resolutionError = m1_moreSpecific == m2_moreSpecific;
+            selectedMethod = m1_moreSpecific ? m1 : m2;
+        } else {
+            selectedMethod = m1_applicable ?
+                m1 : m2;
+        }
+
+        if (res.hasErrors() != resolutionError) {
+            fail("invalid diagnostics for source:\n" +
+                    res.compilationInfo() +
+                    "\nExpected resolution error: " + resolutionError +
+                    "\nFound error: " + res.hasErrors());
+        } else if (!resolutionError) {
+            verifyBytecode(res, selectedMethod);
+        }
+    }
 
+    void verifyBytecode(Result<Iterable<? extends JavaFileObject>> res, VarargsMethod selected) {
+        try (InputStream is = res.get().iterator().next().openInputStream()) {
+            ClassFile cf = ClassFile.read(is);
+            Method testMethod = null;
+            for (Method m : cf.methods) {
+                if (m.getName(cf.constant_pool).equals("test")) {
+                    testMethod = m;
+                    break;
+                }
+            }
+            if (testMethod == null) {
+                fail("Test method not found");
+                return;
+            }
+            Code_attribute ea =
+                (Code_attribute)testMethod.attributes.get(Attribute.Code);
+            if (testMethod == null) {
+                fail("Code attribute for test() method not found");
+                return;
+            }
+
+            for (Instruction i : ea.getInstructions()) {
+                if (i.getMnemonic().equals("invokevirtual")) {
+                    int cp_entry = i.getUnsignedShort(1);
+                    CONSTANT_Methodref_info methRef =
+                        (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry);
+                    String type = methRef.getNameAndTypeInfo().getType();
+                    String sig = selected.parameterTypes.bytecodeSigStr;
+                    if (!type.contains(sig)) {
+                        fail("Unexpected type method call: " +
+                                        type + "" +
+                                        "\nfound: " + sig +
+                                        "\n" + res.compilationInfo());
+                        return;
+                    }
+                    break;
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail("error reading classfile; " + res.compilationInfo() +": " + e);
+        }
+    }
 }
--- a/langtools/test/tools/javac/varargs/warning/Warn4.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/varargs/warning/Warn4.java	Mon Aug 31 17:33:34 2015 +0100
@@ -23,40 +23,39 @@
 
 /**
  * @test
- * @bug     6945418 6993978 8006694 7196160
+ * @bug     6945418 6993978 8006694 7196160 8129962
  * @summary Project Coin: Simplified Varargs Method Invocation
  *  temporarily workaround combo tests are causing time out in several platforms
- * @author  mcimadamore
- * @library ../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm Warn4
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main Warn4
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import java.net.URI;
-import java.util.Arrays;
+import java.io.IOException;
 import java.util.Set;
 import java.util.HashSet;
 import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
+import javax.tools.Diagnostic.Kind;
 import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-import com.sun.source.util.JavacTask;
 
-public class Warn4
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
+
+public class Warn4 extends ComboInstance<Warn4> {
 
     final static Warning[] error = null;
     final static Warning[] none = new Warning[] {};
     final static Warning[] vararg = new Warning[] { Warning.VARARGS };
     final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED };
-    final static Warning[] both =
-            new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
+    final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
 
     enum Warning {
         UNCHECKED("generic.array.creation"),
@@ -105,7 +104,7 @@
         }
     }
 
-    enum TrustMe {
+    enum TrustMe implements ComboParameter {
         DONT_TRUST(""),
         TRUST("@java.lang.SafeVarargs");
 
@@ -114,9 +113,14 @@
         TrustMe(String anno) {
             this.anno = anno;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return anno;
+        }
     }
 
-    enum ModifierKind {
+    enum ModifierKind implements ComboParameter {
         NONE(" "),
         FINAL("final "),
         STATIC("static "),
@@ -127,9 +131,14 @@
         ModifierKind(String mod) {
             this.mod = mod;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return mod;
+        }
     }
 
-    enum SuppressLevel {
+    enum SuppressLevel implements ComboParameter {
         NONE(""),
         UNCHECKED("unchecked");
 
@@ -139,21 +148,22 @@
             this.lint = lint;
         }
 
-        String getSuppressAnno() {
+        @Override
+        public String expand(String optParameter) {
             return "@SuppressWarnings(\"" + lint + "\")";
         }
     }
 
-    enum Signature {
-        UNBOUND("void #name(List<?>#arity arg) { #body }",
+    enum Signature implements ComboParameter {
+        UNBOUND("void #NAME(List<?>#ARITY arg) { #BODY }",
             new Warning[][] {none, none, none, none, error}),
-        INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }",
+        INVARIANT_TVAR("<Z> void #NAME(List<Z>#ARITY arg) { #BODY }",
             new Warning[][] {both, both, error, both, error}),
-        TVAR("<Z> void #name(Z#arity arg) { #body }",
+        TVAR("<Z> void #NAME(Z#ARITY arg) { #BODY }",
             new Warning[][] {both, both, both, both, vararg}),
-        INVARIANT("void #name(List<String>#arity arg) { #body }",
+        INVARIANT("void #NAME(List<String>#ARITY arg) { #BODY }",
             new Warning[][] {error, error, error, both, error}),
-        UNPARAMETERIZED("void #name(String#arity arg) { #body }",
+        UNPARAMETERIZED("void #NAME(String#ARITY arg) { #BODY }",
             new Warning[][] {error, error, error, error, none});
 
         String template;
@@ -177,130 +187,85 @@
             return warnings[other.ordinal()] == vararg ||
                     warnings[other.ordinal()] == both;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            if (optParameter.equals("CLIENT")) {
+                return template.replaceAll("#ARITY", "")
+                        .replaceAll("#NAME", "test")
+                        .replaceAll("#BODY", "m(arg)");
+            } else {
+                return template.replaceAll("#ARITY", "...")
+                        .replaceAll("#NAME", "m")
+                        .replaceAll("#BODY", "");
+            }
+        }
     }
 
-    public static void main(String... args) throws Exception {
-        for (SourceLevel sourceLevel : SourceLevel.values()) {
-            for (TrustMe trustMe : TrustMe.values()) {
-                for (SuppressLevel suppressLevelClient : SuppressLevel.values()) {
-                    for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) {
-                        for (ModifierKind modKind : ModifierKind.values()) {
-                            for (Signature vararg_meth : Signature.values()) {
-                                for (Signature client_meth : Signature.values()) {
-                                    if (vararg_meth.isApplicableTo(client_meth)) {
-                                        pool.execute(new Warn4(sourceLevel,
-                                                trustMe,
-                                                suppressLevelClient,
-                                                suppressLevelDecl,
-                                                modKind,
-                                                vararg_meth,
-                                                client_meth));
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        checkAfterExec();
+    public static void main(String... args) {
+        new ComboTestHelper<Warn4>()
+                .withFilter(Warn4::badTestFilter)
+                .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values())
+                .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values())
+                .withArrayDimension("SUPPRESS", (x, suppress, idx) -> x.suppress[idx] = suppress, 2, SuppressLevel.values())
+                .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values())
+                .withArrayDimension("MTH", (x, sig, idx) -> x.sigs[idx] = sig, 2, Signature.values())
+                .run(Warn4::new);
     }
 
     SourceLevel sourceLevel;
     TrustMe trustMe;
-    SuppressLevel suppressLevelClient;
-    SuppressLevel suppressLevelDecl;
+    SuppressLevel[] suppress = new SuppressLevel[2];
     ModifierKind modKind;
-    Signature vararg_meth;
-    Signature client_meth;
-    DiagnosticChecker diagChecker;
+    Signature[] sigs = new Signature[2];
 
-    public Warn4(SourceLevel sourceLevel, TrustMe trustMe,
-            SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl,
-            ModifierKind modKind, Signature vararg_meth, Signature client_meth) {
-        this.sourceLevel = sourceLevel;
-        this.trustMe = trustMe;
-        this.suppressLevelClient = suppressLevelClient;
-        this.suppressLevelDecl = suppressLevelDecl;
-        this.modKind = modKind;
-        this.vararg_meth = vararg_meth;
-        this.client_meth = client_meth;
-        this.diagChecker = new DiagnosticChecker();
+    boolean badTestFilter() {
+        return sigs[0].isApplicableTo(sigs[1]);
     }
 
+    final String template = "import java.util.List;\n" +
+                            "class Test {\n" +
+                            "   #{TRUSTME} #{SUPPRESS[0]} #{MOD} #{MTH[0].VARARG}\n" +
+                            "   #{SUPPRESS[1]} #{MTH[1].CLIENT}\n" +
+                            "}";
+
     @Override
-    public void run() {
-        int id = checkCount.incrementAndGet();
-        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
-        JavaSource source = new JavaSource(id);
-        JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker,
-                Arrays.asList("-Xlint:unchecked", "-source", sourceLevel.sourceKey),
-                null, Arrays.asList(source));
-        ct.call(); //to get mandatory notes
-        check(source, new boolean[] {vararg_meth.giveUnchecked(client_meth),
-                               vararg_meth.giveVarargs(client_meth)});
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withOption("-Xlint:unchecked")
+                .withOption("-source")
+                .withOption(sourceLevel.sourceKey)
+                .withSourceFromTemplate(template)
+                .analyze());
     }
 
-    void check(JavaSource source, boolean[] warnArr) {
+    void check(Result<?> res) {
+        boolean[] warnArr = new boolean[] {sigs[0].giveUnchecked(sigs[1]),
+                               sigs[0].giveVarargs(sigs[1])};
+
+        Set<Warning> warnings = new HashSet<>();
+        for (Diagnostic<? extends JavaFileObject> d : res.diagnosticsForKind(Kind.MANDATORY_WARNING)) {
+            if (d.getCode().contains(Warning.VARARGS.key)) {
+                    warnings.add(Warning.VARARGS);
+            } else if(d.getCode().contains(Warning.UNCHECKED.key)) {
+                warnings.add(Warning.UNCHECKED);
+            }
+        }
+
         boolean badOutput = false;
         for (Warning wkind : Warning.values()) {
             boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel,
-                    suppressLevelClient, suppressLevelDecl, modKind);
+                    suppress[1], suppress[0], modKind);
             badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) !=
-                    diagChecker.warnings.contains(wkind);
+                    warnings.contains(wkind);
         }
         if (badOutput) {
-            throw new Error("invalid diagnostics for source:\n" +
-                    source.getCharContent(true) +
+            fail("invalid diagnostics for source:\n" +
+                    res.compilationInfo() +
                     "\nExpected unchecked warning: " + warnArr[0] +
                     "\nExpected unsafe vararg warning: " + warnArr[1] +
-                    "\nWarnings: " + diagChecker.warnings +
+                    "\nWarnings: " + warnings +
                     "\nSource level: " + sourceLevel);
         }
     }
-
-    class JavaSource extends SimpleJavaFileObject {
-
-        String source;
-
-        public JavaSource(int id) {
-            super(URI.create(String.format("myfo:/Test%d.java", id)),
-                    JavaFileObject.Kind.SOURCE);
-            String meth1 = vararg_meth.template.replace("#arity", "...");
-            meth1 = meth1.replace("#name", "m");
-            meth1 = meth1.replace("#body", "");
-            meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() +
-                    modKind.mod + meth1;
-            String meth2 = client_meth.template.replace("#arity", "");
-            meth2 = meth2.replace("#name", "test");
-            meth2 = meth2.replace("#body", "m(arg);");
-            meth2 = suppressLevelClient.getSuppressAnno() + meth2;
-            source = String.format("import java.util.List;\n" +
-                     "class Test%s {\n %s \n %s \n } \n", id, meth1, meth2);
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
-        }
-    }
-
-    static class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        Set<Warning> warnings = new HashSet<>();
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING ||
-                    diagnostic.getKind() == Diagnostic.Kind.WARNING) {
-                if (diagnostic.getCode().contains(Warning.VARARGS.key)) {
-                    warnings.add(Warning.VARARGS);
-                } else if(diagnostic.getCode().contains(Warning.UNCHECKED.key)) {
-                    warnings.add(Warning.UNCHECKED);
-                }
-            }
-        }
-    }
-
 }
--- a/langtools/test/tools/javac/varargs/warning/Warn5.java	Mon Aug 31 15:50:20 2015 +0100
+++ b/langtools/test/tools/javac/varargs/warning/Warn5.java	Mon Aug 31 17:33:34 2015 +0100
@@ -26,29 +26,30 @@
  * @bug     6993978 7097436 8006694 7196160
  * @summary Project Coin: Annotation to reduce varargs warnings
  *  temporarily workaround combo tests are causing time out in several platforms
- * @author  mcimadamore
- * @library ../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.comp
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
  * @run main/othervm Warn5
  */
 
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import java.net.URI;
-import java.util.Arrays;
+import java.io.IOException;
 import java.util.EnumSet;
 import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
+import javax.tools.Diagnostic.Kind;
 import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-import com.sun.source.util.JavacTask;
 
-public class Warn5
-    extends JavacTestingAbstractThreadedTest
-    implements Runnable {
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
+
+
+public class Warn5 extends ComboInstance<Warn5> {
 
     enum XlintOption {
         NONE("none"),
@@ -65,7 +66,7 @@
         }
     }
 
-    enum TrustMe {
+    enum TrustMe implements ComboParameter {
         DONT_TRUST(""),
         TRUST("@java.lang.SafeVarargs");
 
@@ -74,20 +75,26 @@
         TrustMe(String anno) {
             this.anno = anno;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return anno;
+        }
     }
 
-    enum SuppressLevel {
+    enum SuppressLevel implements ComboParameter {
         NONE,
         VARARGS;
 
-        String getSuppressAnno() {
+        @Override
+        public String expand(String optParameter) {
             return this == VARARGS ?
                 "@SuppressWarnings(\"varargs\")" :
                 "";
         }
     }
 
-    enum ModifierKind {
+    enum ModifierKind implements ComboParameter {
         NONE(""),
         FINAL("final"),
         STATIC("static"),
@@ -98,9 +105,14 @@
         ModifierKind(String mod) {
             this.mod = mod;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return mod;
+        }
     }
 
-    enum MethodKind {
+    enum MethodKind implements ComboParameter {
         METHOD("void m"),
         CONSTRUCTOR("Test");
 
@@ -109,6 +121,11 @@
         MethodKind(String name) {
             this.name = name;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return name;
+        }
     }
 
     enum SourceLevel {
@@ -123,11 +140,11 @@
         }
     }
 
-    enum SignatureKind {
-        VARARGS_X("#K <X>#N(X... x)", false, true),
-        VARARGS_STRING("#K #N(String... x)", true, true),
-        ARRAY_X("#K <X>#N(X[] x)", false, false),
-        ARRAY_STRING("#K #N(String[] x)", true, false);
+    enum SignatureKind implements ComboParameter {
+        VARARGS_X("<X>#{NAME}(X... x)", false, true),
+        VARARGS_STRING("#{NAME}(String... x)", true, true),
+        ARRAY_X("<X>#{NAME}(X[] x)", false, false),
+        ARRAY_STRING("#{NAME}(String[] x)", true, false);
 
         String stub;
         boolean isReifiableArg;
@@ -139,14 +156,13 @@
             this.isVarargs = isVarargs;
         }
 
-        String getSignature(ModifierKind modKind, MethodKind methKind) {
-            return methKind != MethodKind.CONSTRUCTOR ?
-                stub.replace("#K", modKind.mod).replace("#N", methKind.name) :
-                stub.replace("#K", "").replace("#N", methKind.name);
+        @Override
+        public String expand(String optParameter) {
+            return stub;
         }
     }
 
-    enum BodyKind {
+    enum BodyKind implements ComboParameter {
         ASSIGN("Object o = x;", true),
         CAST("Object o = (Object)x;", true),
         METH("test(x);", true),
@@ -162,82 +178,84 @@
             this.body = body;
             this.hasAliasing = hasAliasing;
         }
+
+        @Override
+        public String expand(String optParameter) {
+            return body;
+        }
     }
 
     enum WarningKind {
-        UNSAFE_BODY,
-        UNSAFE_DECL,
-        MALFORMED_SAFEVARARGS,
-        REDUNDANT_SAFEVARARGS;
+        UNSAFE_BODY("compiler.warn.varargs.unsafe.use.varargs.param"),
+        UNSAFE_DECL("compiler.warn.unchecked.varargs.non.reifiable.type"),
+        MALFORMED_SAFEVARARGS("compiler.err.varargs.invalid.trustme.anno"),
+        REDUNDANT_SAFEVARARGS("compiler.warn.varargs.redundant.trustme.anno");
+
+        String code;
+
+        WarningKind(String code) {
+            this.code = code;
+        }
+    }
+
+    public static void main(String[] args) {
+        new ComboTestHelper<Warn5>()
+                .withFilter(Warn5::badTestFilter)
+                .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values())
+                .withDimension("LINT", (x, lint) -> x.xlint = lint, XlintOption.values())
+                .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values())
+                .withDimension("SUPPRESS", (x, suppress) -> x.suppressLevel = suppress, SuppressLevel.values())
+                .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values())
+                .withDimension("NAME", (x, name) -> x.methKind = name, MethodKind.values())
+                .withDimension("SIG", (x, sig) -> x.sig = sig, SignatureKind.values())
+                .withDimension("BODY", (x, body) -> x.body = body, BodyKind.values())
+                .run(Warn5::new);
     }
 
-    public static void main(String... args) throws Exception {
-        for (SourceLevel sourceLevel : SourceLevel.values()) {
-            for (XlintOption xlint : XlintOption.values()) {
-                for (TrustMe trustMe : TrustMe.values()) {
-                    for (SuppressLevel suppressLevel : SuppressLevel.values()) {
-                        for (ModifierKind modKind : ModifierKind.values()) {
-                            for (MethodKind methKind : MethodKind.values()) {
-                                for (SignatureKind sig : SignatureKind.values()) {
-                                    for (BodyKind body : BodyKind.values()) {
-                                        pool.execute(new Warn5(sourceLevel,
-                                                xlint, trustMe, suppressLevel,
-                                                modKind, methKind, sig, body));
-                                    }
-                                }
-                            }
-                        }
+    SourceLevel sourceLevel;
+    XlintOption xlint;
+    TrustMe trustMe;
+    SuppressLevel suppressLevel;
+    ModifierKind modKind;
+    MethodKind methKind;
+    SignatureKind sig;
+    BodyKind body;
+
+    boolean badTestFilter() {
+        return (methKind != MethodKind.CONSTRUCTOR || modKind == ModifierKind.NONE);
+    }
+
+    String template = "import com.sun.tools.javac.api.*;\n" +
+                      "import java.util.List;\n" +
+                      "class Test {\n" +
+                      "   static void test(Object o) {}\n" +
+                      "   static void testArr(Object[] o) {}\n" +
+                      "   #{TRUSTME} #{SUPPRESS} #{MOD} #{SIG} { #{BODY} }\n" +
+                      "}\n";
+
+    @Override
+    public void doWork() throws IOException {
+        check(newCompilationTask()
+                .withOption(xlint.getXlintOption())
+                .withOption("-source")
+                .withOption(sourceLevel.sourceKey)
+                .withSourceFromTemplate(template)
+                .analyze());
+    }
+
+    void check(Result<?> res) {
+
+        EnumSet<WarningKind> foundWarnings = EnumSet.noneOf(WarningKind.class);
+        for (Diagnostic.Kind kind : new Kind[] { Kind.ERROR, Kind.MANDATORY_WARNING, Kind.WARNING}) {
+            for (Diagnostic<? extends JavaFileObject> diag : res.diagnosticsForKind(kind)) {
+                for (WarningKind wk : WarningKind.values()) {
+                    if (wk.code.equals(diag.getCode())) {
+                        foundWarnings.add(wk);
                     }
                 }
             }
         }
 
-        checkAfterExec(false);
-    }
-
-    final SourceLevel sourceLevel;
-    final XlintOption xlint;
-    final TrustMe trustMe;
-    final SuppressLevel suppressLevel;
-    final ModifierKind modKind;
-    final MethodKind methKind;
-    final SignatureKind sig;
-    final BodyKind body;
-    final JavaSource source;
-    final DiagnosticChecker dc;
-
-    public Warn5(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe,
-            SuppressLevel suppressLevel, ModifierKind modKind,
-            MethodKind methKind, SignatureKind sig, BodyKind body) {
-        this.sourceLevel = sourceLevel;
-        this.xlint = xlint;
-        this.trustMe = trustMe;
-        this.suppressLevel = suppressLevel;
-        this.modKind = modKind;
-        this.methKind = methKind;
-        this.sig = sig;
-        this.body = body;
-        this.source = new JavaSource();
-        this.dc = new DiagnosticChecker();
-    }
-
-    @Override
-    public void run() {
-        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
-        JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), dc,
-                Arrays.asList(xlint.getXlintOption(),
-                    "-source", sourceLevel.sourceKey),
-                null, Arrays.asList(source));
-        try {
-            ct.analyze();
-        } catch (Throwable t) {
-            processException(t);
-        }
-        check();
-    }
-
-    void check() {
-
         EnumSet<WarningKind> expectedWarnings =
                 EnumSet.noneOf(WarningKind.class);
 
@@ -284,77 +302,14 @@
             expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS);
         }
 
-        if (!expectedWarnings.containsAll(dc.warnings) ||
-                !dc.warnings.containsAll(expectedWarnings)) {
-            throw new Error("invalid diagnostics for source:\n" +
-                    source.getCharContent(true) +
+        if (!expectedWarnings.containsAll(foundWarnings) ||
+                !foundWarnings.containsAll(expectedWarnings)) {
+            fail("invalid diagnostics for source:\n" +
+                    res.compilationInfo() +
                     "\nOptions: " + xlint.getXlintOption() +
                     "\nSource Level: " + sourceLevel +
                     "\nExpected warnings: " + expectedWarnings +
-                    "\nFound warnings: " + dc.warnings);
-        }
-    }
-
-    class JavaSource extends SimpleJavaFileObject {
-
-        String template = "import com.sun.tools.javac.api.*;\n" +
-                          "import java.util.List;\n" +
-                          "class Test {\n" +
-                          "   static void test(Object o) {}\n" +
-                          "   static void testArr(Object[] o) {}\n" +
-                          "   #T \n #S #M { #B }\n" +
-                          "}\n";
-
-        String source;
-
-        public JavaSource() {
-            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
-            source = template.replace("#T", trustMe.anno).
-                    replace("#S", suppressLevel.getSuppressAnno()).
-                    replace("#M", sig.getSignature(modKind, methKind)).
-                    replace("#B", body.body);
-        }
-
-        @Override
-        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
-            return source;
+                    "\nFound warnings: " + foundWarnings);
         }
     }
-
-    class DiagnosticChecker
-        implements javax.tools.DiagnosticListener<JavaFileObject> {
-
-        EnumSet<WarningKind> warnings = EnumSet.noneOf(WarningKind.class);
-
-        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
-            if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
-                    if (diagnostic.getCode().
-                            contains("unsafe.use.varargs.param")) {
-                        setWarning(WarningKind.UNSAFE_BODY);
-                    } else if (diagnostic.getCode().
-                            contains("redundant.trustme")) {
-                        setWarning(WarningKind.REDUNDANT_SAFEVARARGS);
-                    }
-            } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
-                    diagnostic.getCode().
-                        contains("varargs.non.reifiable.type")) {
-                setWarning(WarningKind.UNSAFE_DECL);
-            } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
-                    diagnostic.getCode().contains("invalid.trustme")) {
-                setWarning(WarningKind.MALFORMED_SAFEVARARGS);
-            }
-        }
-
-        void setWarning(WarningKind wk) {
-            if (!warnings.add(wk)) {
-                throw new AssertionError("Duplicate warning of kind " +
-                        wk + " in source:\n" + source);
-            }
-        }
-
-        boolean hasWarning(WarningKind wk) {
-            return warnings.contains(wk);
-        }
-    }
-
 }