8078093: Severe compiler performance regression Java 7 to 8 for nested method invocations
authormcimadamore
Tue, 15 Sep 2015 13:43:44 +0100
changeset 32709 55d136799f79
parent 32708 1a5b80de4f57
child 32710 a5249bcec60f
8078093: Severe compiler performance regression Java 7 to 8 for nested method invocations Summary: Add infrastructure to avoid combinatorial explosion of method argument attributions Reviewed-by: jlahoda, vromero, dlsmith
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
langtools/test/tools/javac/generics/wildcards/neg/Readonly.out
langtools/test/tools/javac/lambda/8019480/T8019480.out
langtools/test/tools/javac/lambda/speculative/InferStrict.java
langtools/test/tools/javac/lambda/speculative/InferWeak.java
langtools/test/tools/javac/lambda/speculative/NestedLambdaGenerics.java
langtools/test/tools/javac/lambda/speculative/NestedLambdaNoGenerics.java
langtools/test/tools/javac/lambda/speculative/T8055984.java
langtools/test/tools/javac/lambda/speculative/T8077247.java
langtools/test/tools/javac/lambda/speculative/T8078093.java
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Mon Sep 14 11:26:14 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Tue Sep 15 13:43:44 2015 +0100
@@ -3152,10 +3152,20 @@
                 throw new IllegalArgumentException("Not a method type: " + t);
             }
             public Type visitMethodType(MethodType t, Type newReturn) {
-                return new MethodType(t.argtypes, newReturn, t.thrown, t.tsym);
+                return new MethodType(t.argtypes, newReturn, t.thrown, t.tsym) {
+                    @Override
+                    public Type baseType() {
+                        return t;
+                    }
+                };
             }
             public Type visitForAll(ForAll t, Type newReturn) {
-                return new ForAll(t.tvars, t.qtype.accept(this, newReturn));
+                return new ForAll(t.tvars, t.qtype.accept(this, newReturn)) {
+                    @Override
+                    public Type baseType() {
+                        return t;
+                    }
+                };
             }
         };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java	Tue Sep 15 13:43:44 2015 +0100
@@ -0,0 +1,679 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.javac.comp;
+
+import com.sun.source.tree.LambdaExpressionTree.BodyKind;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
+import com.sun.tools.javac.comp.Attr.ResultInfo;
+import com.sun.tools.javac.comp.Attr.TargetInfo;
+import com.sun.tools.javac.comp.Check.CheckContext;
+import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredTypeCompleter;
+import com.sun.tools.javac.comp.DeferredAttr.LambdaReturnScanner;
+import com.sun.tools.javac.comp.Infer.PartiallyInferredMethodType;
+import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCConditional;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCLambda;
+import com.sun.tools.javac.tree.JCTree.JCLambda.ParameterKind;
+import com.sun.tools.javac.tree.JCTree.JCMemberReference;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCNewClass;
+import com.sun.tools.javac.tree.JCTree.JCParens;
+import com.sun.tools.javac.tree.JCTree.JCReturn;
+import com.sun.tools.javac.tree.TreeCopier;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.DiagnosticSource;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Log;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import static com.sun.tools.javac.code.TypeTag.DEFERRED;
+import static com.sun.tools.javac.code.TypeTag.FORALL;
+import static com.sun.tools.javac.code.TypeTag.METHOD;
+import static com.sun.tools.javac.code.TypeTag.VOID;
+
+/**
+ * This class performs attribution of method/constructor arguments when target-typing is enabled
+ * (source >= 8); for each argument that is potentially a poly expression, this class builds
+ * a rich representation (see {@link ArgumentType} which can then be used for performing fast overload
+ * checks without requiring multiple attribution passes over the same code.
+ *
+ * The attribution strategy for a given method/constructor argument A is as follows:
+ *
+ * - if A is potentially a poly expression (i.e. diamond instance creation expression), a speculative
+ * pass over A is performed; the results of such speculative attribution are then saved in a special
+ * type, so that enclosing overload resolution can be carried by simply checking compatibility against the
+ * type determined during this speculative pass.
+ *
+ * - if A is a standalone expression, regular atributtion takes place.
+ *
+ * To minimize the speculative work, a cache is used, so that already computed argument types
+ * associated with a given unique source location are never recomputed multiple times.
+ */
+public class ArgumentAttr extends JCTree.Visitor {
+
+    protected static final Context.Key<ArgumentAttr> methodAttrKey = new Context.Key<>();
+
+    private final DeferredAttr deferredAttr;
+    private final Attr attr;
+    private final Symtab syms;
+    private final Log log;
+
+    /** Attribution environment to be used. */
+    private Env<AttrContext> env;
+
+    /** Result of method attribution. */
+    private Type result;
+
+    /** Cache for argument types; behavior is influences by the currrently selected cache policy. */
+    Map<UniquePos, ArgumentType<?>> argumentTypeCache = new LinkedHashMap<>();
+
+    /** Cache policy: should argument types be cached? */
+    private CachePolicy cachePolicy = CachePolicy.CACHE;
+
+    public static ArgumentAttr instance(Context context) {
+        ArgumentAttr instance = context.get(methodAttrKey);
+        if (instance == null)
+            instance = new ArgumentAttr(context);
+        return instance;
+    }
+
+    protected ArgumentAttr(Context context) {
+        context.put(methodAttrKey, this);
+        deferredAttr = DeferredAttr.instance(context);
+        attr = Attr.instance(context);
+        syms = Symtab.instance(context);
+        log = Log.instance(context);
+    }
+
+    /**
+     * Set the results of method attribution.
+     */
+    void setResult(JCExpression tree, Type type) {
+        result = type;
+        if (env.info.isSpeculative) {
+            //if we are in a speculative branch we can save the type in the tree itself
+            //as there's no risk of polluting the original tree.
+            tree.type = result;
+        }
+    }
+
+    /**
+     * Checks a type in the speculative tree against a given result; the type can be either a plain
+     * type or an argument type,in which case a more complex check is required.
+     */
+    Type checkSpeculative(JCExpression expr, ResultInfo resultInfo) {
+        return checkSpeculative(expr, expr.type, resultInfo);
+    }
+
+    /**
+     * Checks a type in the speculative tree against a given result; the type can be either a plain
+     * type or an argument type,in which case a more complex check is required.
+     */
+    Type checkSpeculative(DiagnosticPosition pos, Type t, ResultInfo resultInfo) {
+        if (t.hasTag(DEFERRED)) {
+            return ((DeferredType)t).check(resultInfo);
+        } else {
+            return resultInfo.check(pos, t);
+        }
+    }
+
+    /**
+     * Sets given ache policy and returns current policy.
+     */
+    CachePolicy withCachePolicy(CachePolicy newPolicy) {
+        CachePolicy oldPolicy = this.cachePolicy;
+        this.cachePolicy = newPolicy;
+        return oldPolicy;
+    }
+
+    /**
+     * Main entry point for attributing an argument with given tree and attribution environment.
+     */
+    Type attribArg(JCTree tree, Env<AttrContext> env) {
+        Env<AttrContext> prevEnv = this.env;
+        try {
+            this.env = env;
+            tree.accept(this);
+            return result;
+        } finally {
+            this.env = prevEnv;
+        }
+    }
+
+    @Override
+    public void visitTree(JCTree that) {
+        //delegates to Attr
+        that.accept(attr);
+        result = attr.result;
+    }
+
+    /**
+     * Process a method argument; this method takes care of performing a speculative pass over the
+     * argument tree and calling a well-defined entry point to build the argument type associated
+     * with such tree.
+     */
+    @SuppressWarnings("unchecked")
+    <T extends JCExpression, Z extends ArgumentType<T>> void processArg(T that, Function<T, Z> argumentTypeFactory) {
+        UniquePos pos = new UniquePos(that);
+        processArg(that, () -> {
+            T speculativeTree = (T)deferredAttr.attribSpeculative(that, env, attr.new MethodAttrInfo() {
+                @Override
+                protected void attr(JCTree tree, Env<AttrContext> env) {
+                    //avoid speculative attribution loops
+                    if (!new UniquePos(tree).equals(pos)) {
+                        super.attr(tree, env);
+                    } else {
+                        visitTree(tree);
+                    }
+                }
+            });
+            return argumentTypeFactory.apply(speculativeTree);
+        });
+    }
+
+    /**
+     * Process a method argument; this method allows the caller to specify a custom speculative attribution
+     * logic (this is used e.g. for lambdas).
+     */
+    @SuppressWarnings("unchecked")
+    <T extends JCExpression, Z extends ArgumentType<T>> void processArg(T that, Supplier<Z> argumentTypeFactory) {
+        UniquePos pos = new UniquePos(that);
+        Z cached = (Z)argumentTypeCache.get(pos);
+        if (cached != null) {
+            //dup existing speculative type
+            setResult(that, cached.dup(that, env));
+        } else {
+            Z res = argumentTypeFactory.get();
+            if (cachePolicy == CachePolicy.CACHE) {
+                argumentTypeCache.put(pos, res);
+            }
+            setResult(that, res);
+        }
+    }
+
+    @Override
+    public void visitParens(JCParens that) {
+        processArg(that, speculativeTree -> new ParensType(that, env, speculativeTree));
+    }
+
+    @Override
+    public void visitConditional(JCConditional that) {
+        processArg(that, speculativeTree -> new ConditionalType(that, env, speculativeTree));
+    }
+
+    @Override
+    public void visitReference(JCMemberReference tree) {
+        //perform arity-based check
+        Env<AttrContext> localEnv = env.dup(tree);
+        JCExpression exprTree = (JCExpression)deferredAttr.attribSpeculative(tree.getQualifierExpression(), localEnv,
+                attr.memberReferenceQualifierResult(tree));
+        JCMemberReference mref2 = new TreeCopier<Void>(attr.make).copy(tree);
+        mref2.expr = exprTree;
+        Symbol res =
+                attr.rs.getMemberReference(tree, localEnv, mref2,
+                        exprTree.type, tree.name);
+        if (!res.kind.isResolutionError()) {
+            tree.sym = res;
+        }
+        if (res.kind.isResolutionTargetError() ||
+                res.type != null && res.type.hasTag(FORALL) ||
+                (res.flags() & Flags.VARARGS) != 0 ||
+                (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
+                exprTree.type.isRaw())) {
+            tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
+        } else {
+            tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
+        }
+        //return a plain old deferred type for this
+        setResult(tree, deferredAttr.new DeferredType(tree, env));
+    }
+
+    @Override
+    public void visitLambda(JCLambda that) {
+        if (that.paramKind == ParameterKind.EXPLICIT) {
+            //if lambda is explicit, we can save info in the corresponding argument type
+            processArg(that, () -> {
+                JCLambda speculativeLambda =
+                        deferredAttr.attribSpeculativeLambda(that, env, attr.methodAttrInfo);
+                return new ExplicitLambdaType(that, env, speculativeLambda);
+            });
+        } else {
+            //otherwise just use a deferred type
+            setResult(that, deferredAttr.new DeferredType(that, env));
+        }
+    }
+
+    @Override
+    public void visitApply(JCMethodInvocation that) {
+        if (that.getTypeArguments().isEmpty()) {
+            processArg(that, speculativeTree -> new ResolvedMethodType(that, env, speculativeTree));
+        } else {
+            //not a poly expression, just call Attr
+            setResult(that, attr.attribTree(that, env, attr.unknownExprInfo));
+        }
+    }
+
+    @Override
+    public void visitNewClass(JCNewClass that) {
+        if (TreeInfo.isDiamond(that)) {
+            processArg(that, speculativeTree -> new ResolvedConstructorType(that, env, speculativeTree));
+        } else {
+            //not a poly expression, just call Attr
+            setResult(that, attr.attribTree(that, env, attr.unknownExprInfo));
+        }
+    }
+
+    /**
+     * An argument type is similar to a plain deferred type; the most important difference is that
+     * the completion logic associated with argument types allows speculative attribution to be skipped
+     * during overload resolution - that is, an argument type always has enough information to
+     * perform an overload check without the need of calling back to Attr. This extra information
+     * is typically stored in the form of a speculative tree.
+     */
+    abstract class ArgumentType<T extends JCExpression> extends DeferredType implements DeferredTypeCompleter {
+
+        /** The speculative tree carrying type information. */
+        T speculativeTree;
+
+        /** Types associated with this argument (one type per possible target result). */
+        Map<ResultInfo, Type> speculativeTypes;
+
+        public ArgumentType(JCExpression tree, Env<AttrContext> env, T speculativeTree, Map<ResultInfo, Type> speculativeTypes) {
+            deferredAttr.super(tree, env);
+            this.speculativeTree = speculativeTree;
+            this.speculativeTypes = speculativeTypes;
+        }
+
+        @Override
+        final DeferredTypeCompleter completer() {
+            return this;
+        }
+
+        @Override
+        final public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
+            Assert.check(dt == this);
+            if (deferredAttrContext.mode == AttrMode.SPECULATIVE) {
+                Type t = (resultInfo.pt == Type.recoveryType) ?
+                        deferredAttr.basicCompleter.complete(dt, resultInfo, deferredAttrContext) :
+                        overloadCheck(resultInfo, deferredAttrContext);
+                speculativeTypes.put(resultInfo, t);
+                return t;
+            } else {
+                if (!env.info.isSpeculative && cachePolicy == CachePolicy.CACHE) {
+                    argumentTypeCache.remove(new UniquePos(dt.tree));
+                }
+                return deferredAttr.basicCompleter.complete(dt, resultInfo, deferredAttrContext);
+            }
+        }
+
+        @Override
+        Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
+            for (Map.Entry<ResultInfo, Type> _entry : speculativeTypes.entrySet()) {
+                DeferredAttrContext deferredAttrContext = _entry.getKey().checkContext.deferredAttrContext();
+                if (deferredAttrContext.phase == phase && deferredAttrContext.msym == msym) {
+                    return _entry.getValue();
+                }
+            }
+            return Type.noType;
+        }
+
+        @Override
+        JCTree speculativeTree(DeferredAttrContext deferredAttrContext) {
+            return speculativeTree;
+        }
+
+        /**
+         * Performs an overload check against a given target result.
+         */
+        abstract Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
+
+        /**
+         * Creates a copy of this argument type with given tree and environment.
+         */
+        abstract ArgumentType<T> dup(T tree, Env<AttrContext> env);
+    }
+
+    /**
+     * Argument type for parenthesized expression.
+     */
+    class ParensType extends ArgumentType<JCParens> {
+        ParensType(JCExpression tree, Env<AttrContext> env, JCParens speculativeParens) {
+            this(tree, env, speculativeParens, new HashMap<>());
+        }
+
+        ParensType(JCExpression tree, Env<AttrContext> env, JCParens speculativeParens, Map<ResultInfo, Type> speculativeTypes) {
+           super(tree, env, speculativeParens, speculativeTypes);
+        }
+
+        @Override
+        Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
+            return checkSpeculative(speculativeTree.expr, resultInfo);
+        }
+
+        @Override
+        ArgumentType<JCParens> dup(JCParens tree, Env<AttrContext> env) {
+            return new ParensType(tree, env, speculativeTree, speculativeTypes);
+        }
+    }
+
+    /**
+     * Argument type for conditionals.
+     */
+    class ConditionalType extends ArgumentType<JCConditional> {
+        ConditionalType(JCExpression tree, Env<AttrContext> env, JCConditional speculativeCond) {
+            this(tree, env, speculativeCond, new HashMap<>());
+        }
+
+        ConditionalType(JCExpression tree, Env<AttrContext> env, JCConditional speculativeCond, Map<ResultInfo, Type> speculativeTypes) {
+           super(tree, env, speculativeCond, speculativeTypes);
+        }
+
+        @Override
+        Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
+            ResultInfo localInfo = resultInfo.dup(attr.conditionalContext(resultInfo.checkContext));
+            if (speculativeTree.isStandalone()) {
+                return localInfo.check(speculativeTree, speculativeTree.type);
+            } else if (resultInfo.pt.hasTag(VOID)) {
+                //this means we are returning a poly conditional from void-compatible lambda expression
+                resultInfo.checkContext.report(tree, attr.diags.fragment("conditional.target.cant.be.void"));
+                return attr.types.createErrorType(resultInfo.pt);
+            } else {
+                //poly
+                checkSpeculative(speculativeTree.truepart, localInfo);
+                checkSpeculative(speculativeTree.falsepart, localInfo);
+                return localInfo.pt;
+            }
+        }
+
+        @Override
+        ArgumentType<JCConditional> dup(JCConditional tree, Env<AttrContext> env) {
+            return new ConditionalType(tree, env, speculativeTree, speculativeTypes);
+        }
+    }
+
+    /**
+     * Argument type for explicit lambdas.
+     */
+    class ExplicitLambdaType extends ArgumentType<JCLambda> {
+
+        /** List of argument types (lazily populated). */
+        Optional<List<Type>> argtypes = Optional.empty();
+
+        /** List of return expressions (lazily populated). */
+        Optional<List<JCReturn>> returnExpressions = Optional.empty();
+
+        ExplicitLambdaType(JCLambda originalLambda, Env<AttrContext> env, JCLambda speculativeLambda) {
+            this(originalLambda, env, speculativeLambda, new HashMap<>());
+        }
+
+        ExplicitLambdaType(JCLambda originalLambda, Env<AttrContext> env, JCLambda speculativeLambda, Map<ResultInfo, Type> speculativeTypes) {
+            super(originalLambda, env, speculativeLambda, speculativeTypes);
+        }
+
+        /** Compute argument types (if needed). */
+        List<Type> argtypes() {
+            return argtypes.orElseGet(() -> {
+                List<Type> res = TreeInfo.types(speculativeTree.params);
+                argtypes = Optional.of(res);
+                return res;
+            });
+        }
+
+        /** Compute return expressions (if needed). */
+        List<JCReturn> returnExpressions() {
+            return returnExpressions.orElseGet(() -> {
+                final List<JCReturn> res;
+                if (speculativeTree.getBodyKind() == BodyKind.EXPRESSION) {
+                    res = List.of(attr.make.Return((JCExpression)speculativeTree.body));
+                } else {
+                    ListBuffer<JCReturn> returnExpressions = new ListBuffer<>();
+                    new LambdaReturnScanner() {
+                        @Override
+                        public void visitReturn(JCReturn tree) {
+                            returnExpressions.add(tree);
+                        }
+                    }.scan(speculativeTree.body);
+                    res = returnExpressions.toList();
+                }
+                returnExpressions = Optional.of(res);
+                return res;
+            });
+        }
+
+        @Override
+        Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
+            try {
+                //compute target-type; this logic could be shared with Attr
+                TargetInfo targetInfo = attr.getTargetInfo(speculativeTree, resultInfo, argtypes());
+                Type lambdaType = targetInfo.descriptor;
+                Type currentTarget = targetInfo.target;
+                //check compatibility
+                checkLambdaCompatible(lambdaType, resultInfo);
+                return currentTarget;
+            } catch (FunctionDescriptorLookupError ex) {
+                resultInfo.checkContext.report(null, ex.getDiagnostic());
+                return null; //cannot get here
+            }
+        }
+
+        /** Check lambda against given target result */
+        private void checkLambdaCompatible(Type descriptor, ResultInfo resultInfo) {
+            CheckContext checkContext = resultInfo.checkContext;
+            ResultInfo bodyResultInfo = attr.lambdaBodyResult(speculativeTree, descriptor, resultInfo);
+            for (JCReturn ret : returnExpressions()) {
+                Type t = getReturnType(ret);
+                if (speculativeTree.getBodyKind() == BodyKind.EXPRESSION || !t.hasTag(VOID)) {
+                    checkSpeculative(ret.expr, t, bodyResultInfo);
+                }
+            }
+
+            attr.checkLambdaCompatible(speculativeTree, descriptor, checkContext);
+        }
+
+        /** Get the type associated with given return expression. */
+        Type getReturnType(JCReturn ret) {
+            if (ret.expr == null) {
+                return syms.voidType;
+            } else {
+                return ret.expr.type;
+            }
+        }
+
+        @Override
+        ArgumentType<JCLambda> dup(JCLambda tree, Env<AttrContext> env) {
+            return new ExplicitLambdaType(tree, env, speculativeTree, speculativeTypes);
+        }
+    }
+
+    /**
+     * Argument type for methods/constructors.
+     */
+    abstract class ResolvedMemberType<E extends JCExpression> extends ArgumentType<E> {
+
+        public ResolvedMemberType(JCExpression tree, Env<AttrContext> env, E speculativeMethod, Map<ResultInfo, Type> speculativeTypes) {
+            super(tree, env, speculativeMethod, speculativeTypes);
+        }
+
+        @Override
+        Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
+            Type mtype = methodType();
+            ResultInfo localInfo = resultInfo(resultInfo);
+            if (mtype != null && mtype.hasTag(METHOD) && mtype.isPartial()) {
+                Type t = ((PartiallyInferredMethodType)mtype).check(localInfo);
+                if (!deferredAttrContext.inferenceContext.free(localInfo.pt)) {
+                    speculativeTypes.put(localInfo, t);
+                    return localInfo.check(tree.pos(), t);
+                } else {
+                    return t;
+                }
+            } else {
+                Type t = localInfo.check(tree.pos(), speculativeTree.type);
+                speculativeTypes.put(localInfo, t);
+                return t;
+            }
+        }
+
+        /**
+         * Get the result info to be used for performing an overload check.
+         */
+        abstract ResultInfo resultInfo(ResultInfo resultInfo);
+
+        /**
+         * Get the method type to be used for performing an overload check.
+         */
+        abstract Type methodType();
+    }
+
+    /**
+     * Argument type for methods.
+     */
+    class ResolvedMethodType extends ResolvedMemberType<JCMethodInvocation> {
+
+        public ResolvedMethodType(JCExpression tree, Env<AttrContext> env, JCMethodInvocation speculativeTree) {
+            this(tree, env, speculativeTree, new HashMap<>());
+        }
+
+        public ResolvedMethodType(JCExpression tree, Env<AttrContext> env, JCMethodInvocation speculativeTree, Map<ResultInfo, Type> speculativeTypes) {
+            super(tree, env, speculativeTree, speculativeTypes);
+        }
+
+        @Override
+        ResultInfo resultInfo(ResultInfo resultInfo) {
+            return resultInfo;
+        }
+
+        @Override
+        Type methodType() {
+            return speculativeTree.meth.type;
+        }
+
+        @Override
+        ArgumentType<JCMethodInvocation> dup(JCMethodInvocation tree, Env<AttrContext> env) {
+            return new ResolvedMethodType(tree, env, speculativeTree, speculativeTypes);
+        }
+    }
+
+    /**
+     * Argument type for constructors.
+     */
+    class ResolvedConstructorType extends ResolvedMemberType<JCNewClass> {
+
+        public ResolvedConstructorType(JCExpression tree, Env<AttrContext> env, JCNewClass speculativeTree) {
+            this(tree, env, speculativeTree, new HashMap<>());
+        }
+
+        public ResolvedConstructorType(JCExpression tree, Env<AttrContext> env, JCNewClass speculativeTree, Map<ResultInfo, Type> speculativeTypes) {
+            super(tree, env, speculativeTree, speculativeTypes);
+        }
+
+        @Override
+        ResultInfo resultInfo(ResultInfo resultInfo) {
+            return resultInfo.dup(attr.diamondContext(speculativeTree, speculativeTree.clazz.type.tsym, resultInfo.checkContext));
+        }
+
+        @Override
+        Type methodType() {
+            return (speculativeTree.constructorType != null) ?
+                    speculativeTree.constructorType.baseType() : syms.errType;
+        }
+
+        @Override
+        ArgumentType<JCNewClass> dup(JCNewClass tree, Env<AttrContext> env) {
+            return new ResolvedConstructorType(tree, env, speculativeTree, speculativeTypes);
+        }
+    }
+
+    /**
+     * An instance of this class represents a unique position in a compilation unit. A unique
+     * position is made up of (i) a unique position in a source file (char offset) and (ii)
+     * a source file info.
+     */
+    class UniquePos {
+
+        /** Char offset. */
+        int pos;
+
+        /** Source info. */
+        DiagnosticSource source;
+
+        UniquePos(JCTree tree) {
+            this.pos = tree.pos;
+            this.source = log.currentSource();
+        }
+
+        @Override
+        public int hashCode() {
+            return pos << 16 + source.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof UniquePos) {
+                UniquePos that = (UniquePos)obj;
+                return pos == that.pos && source == that.source;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return source.getFile().getName() + " @ " + source.getLineNumber(pos);
+        }
+    }
+
+    /**
+     * Argument type caching policy.
+     */
+    enum CachePolicy {
+        /** Cache argument types. */
+        CACHE,
+        /**
+         * Don't cache argument types. This is useful when performing speculative attribution on
+         * a tree that is known to contain erroneous info.
+         */
+        NO_CACHE;
+    }
+}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Sep 14 11:26:14 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Sep 15 13:43:44 2015 +0100
@@ -108,6 +108,7 @@
     final TypeEnvs typeEnvs;
     final Dependencies dependencies;
     final Annotate annotate;
+    final ArgumentAttr argumentAttr;
 
     public static Attr instance(Context context) {
         Attr instance = context.get(attrKey);
@@ -142,6 +143,7 @@
         deferredLintHandler = DeferredLintHandler.instance(context);
         typeEnvs = TypeEnvs.instance(context);
         dependencies = Dependencies.instance(context);
+        argumentAttr = ArgumentAttr.instance(context);
 
         Options options = Options.instance(context);
 
@@ -160,7 +162,7 @@
         statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
         varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType);
         unknownExprInfo = new ResultInfo(KindSelector.VAL, Type.noType);
-        unknownAnyPolyInfo = new ResultInfo(KindSelector.VAL, Infer.anyPoly);
+        methodAttrInfo = new MethodAttrInfo();
         unknownTypeInfo = new ResultInfo(KindSelector.TYP, Type.noType);
         unknownTypeExprInfo = new ResultInfo(KindSelector.VAL_TYP, Type.noType);
         recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
@@ -488,6 +490,10 @@
             this.checkMode = checkMode;
         }
 
+        protected void attr(JCTree tree, Env<AttrContext> env) {
+            tree.accept(Attr.this);
+        }
+
         protected Type check(final DiagnosticPosition pos, final Type found) {
             return chk.checkType(pos, found, pt, checkContext);
         }
@@ -522,6 +528,41 @@
         }
     }
 
+    class MethodAttrInfo extends ResultInfo {
+        public MethodAttrInfo() {
+            this(chk.basicHandler);
+        }
+
+        public MethodAttrInfo(CheckContext checkContext) {
+            super(KindSelector.VAL, Infer.anyPoly, checkContext);
+        }
+
+        @Override
+        protected void attr(JCTree tree, Env<AttrContext> env) {
+            result = argumentAttr.attribArg(tree, env);
+        }
+
+        protected ResultInfo dup(Type newPt) {
+            throw new IllegalStateException();
+        }
+
+        protected ResultInfo dup(CheckContext newContext) {
+            return new MethodAttrInfo(newContext);
+        }
+
+        protected ResultInfo dup(Type newPt, CheckContext newContext) {
+            throw new IllegalStateException();
+        }
+
+        protected ResultInfo dup(Type newPt, CheckContext newContext, CheckMode newMode) {
+            throw new IllegalStateException();
+        }
+
+        protected ResultInfo dup(CheckMode newMode) {
+            throw new IllegalStateException();
+        }
+    }
+
     class RecoveryInfo extends ResultInfo {
 
         public RecoveryInfo(final DeferredAttr.DeferredAttrContext deferredAttrContext) {
@@ -545,7 +586,7 @@
 
     final ResultInfo statInfo;
     final ResultInfo varAssignmentInfo;
-    final ResultInfo unknownAnyPolyInfo;
+    final ResultInfo methodAttrInfo;
     final ResultInfo unknownExprInfo;
     final ResultInfo unknownTypeInfo;
     final ResultInfo unknownTypeExprInfo;
@@ -588,7 +629,7 @@
         try {
             this.env = env;
             this.resultInfo = resultInfo;
-            tree.accept(this);
+            resultInfo.attr(tree, env);
             if (tree == breakTree &&
                     resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
                 throw new BreakAttr(copyEnv(env));
@@ -684,12 +725,9 @@
     KindSelector attribArgs(KindSelector initialKind, List<JCExpression> trees, Env<AttrContext> env, ListBuffer<Type> argtypes) {
         KindSelector kind = initialKind;
         for (JCExpression arg : trees) {
-            Type argtype;
-            if (allowPoly && deferredAttr.isDeferred(env, arg)) {
-                argtype = deferredAttr.new DeferredType(arg, env);
+            Type argtype = chk.checkNonVoid(arg, attribTree(arg, env, allowPoly ? methodAttrInfo : unknownExprInfo));
+            if (argtype.hasTag(DEFERRED)) {
                 kind = KindSelector.of(KindSelector.POLY, kind);
-            } else {
-                argtype = chk.checkNonVoid(arg, attribTree(arg, env, unknownAnyPolyInfo));
             }
             argtypes.append(argtype);
         }
@@ -1426,12 +1464,12 @@
         Type condtype = attribExpr(tree.cond, env, syms.booleanType);
 
         tree.polyKind = (!allowPoly ||
-                pt().hasTag(NONE) && pt() != Type.recoveryType ||
+                pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly ||
                 isBooleanOrNumeric(env, tree)) ?
                 PolyKind.STANDALONE : PolyKind.POLY;
 
         if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) {
-            //cannot get here (i.e. it means we are returning from void method - which is already an error)
+            //this means we are returning a poly conditional from void-compatible lambda expression
             resultInfo.checkContext.report(tree, diags.fragment("conditional.target.cant.be.void"));
             result = tree.type = types.createErrorType(resultInfo.pt);
             return;
@@ -1439,15 +1477,7 @@
 
         ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ?
                 unknownExprInfo :
-                resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
-                    //this will use enclosing check context to check compatibility of
-                    //subexpression against target type; if we are in a method check context,
-                    //depending on whether boxing is allowed, we could have incompatibilities
-                    @Override
-                    public void report(DiagnosticPosition pos, JCDiagnostic details) {
-                        enclosingContext.report(pos, diags.fragment("incompatible.type.in.conditional", details));
-                    }
-                });
+                resultInfo.dup(conditionalContext(resultInfo.checkContext));
 
         Type truetype = attribTree(tree.truepart, env, condInfo);
         Type falsetype = attribTree(tree.falsepart, env, condInfo);
@@ -1506,6 +1536,18 @@
                 }
             };
 
+        CheckContext conditionalContext(CheckContext checkContext) {
+            return new Check.NestedCheckContext(checkContext) {
+                //this will use enclosing check context to check compatibility of
+                //subexpression against target type; if we are in a method check context,
+                //depending on whether boxing is allowed, we could have incompatibilities
+                @Override
+                public void report(DiagnosticPosition pos, JCDiagnostic details) {
+                    enclosingContext.report(pos, diags.fragment("incompatible.type.in.conditional", details));
+                }
+            };
+        }
+
         /** Compute the type of a conditional expression, after
          *  checking that it exists.  See JLS 15.25. Does not take into
          *  account the special case where condition and both arms
@@ -2070,13 +2112,8 @@
                 tree.constructor = constructor.baseSymbol();
 
                 final TypeSymbol csym = clazztype.tsym;
-                ResultInfo diamondResult = new ResultInfo(pkind, newMethodTemplate(resultInfo.pt, argtypes, typeargtypes), new Check.NestedCheckContext(resultInfo.checkContext) {
-                    @Override
-                    public void report(DiagnosticPosition _unused, JCDiagnostic details) {
-                        enclosingContext.report(tree.clazz,
-                                diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", csym), details));
-                    }
-                }, CheckMode.NO_TREE_UPDATE);
+                ResultInfo diamondResult = new ResultInfo(pkind, newMethodTemplate(resultInfo.pt, argtypes, typeargtypes),
+                        diamondContext(tree, csym, resultInfo.checkContext), CheckMode.NO_TREE_UPDATE);
                 Type constructorType = tree.constructorType = types.createErrorType(clazztype);
                 constructorType = checkId(tree, site,
                         constructor,
@@ -2261,6 +2298,16 @@
             chk.validate(tree.typeargs, localEnv);
         }
 
+        CheckContext diamondContext(JCNewClass clazz, TypeSymbol tsym, CheckContext checkContext) {
+            return new Check.NestedCheckContext(checkContext) {
+                @Override
+                public void report(DiagnosticPosition _unused, JCDiagnostic details) {
+                    enclosingContext.report(clazz.clazz,
+                            diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", tsym), details));
+                }
+            };
+        }
+
     /** Make an attributed null check tree.
      */
     public JCExpression makeNullCheck(JCExpression arg) {
@@ -2330,8 +2377,7 @@
         boolean needsRecovery =
                 resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
         try {
-            Type currentTarget = pt();
-            if (needsRecovery && isSerializable(currentTarget)) {
+            if (needsRecovery && isSerializable(pt())) {
                 localEnv.info.isSerializable = true;
             }
             List<Type> explicitParamTypes = null;
@@ -2341,22 +2387,13 @@
                 explicitParamTypes = TreeInfo.types(that.params);
             }
 
-            Type lambdaType;
-            if (pt() != Type.recoveryType) {
-                /* We need to adjust the target. If the target is an
-                 * intersection type, for example: SAM & I1 & I2 ...
-                 * the target will be updated to SAM
-                 */
-                currentTarget = targetChecker.visit(currentTarget, that);
-                if (explicitParamTypes != null) {
-                    currentTarget = infer.instantiateFunctionalInterface(that,
-                            currentTarget, explicitParamTypes, resultInfo.checkContext);
-                }
-                currentTarget = types.removeWildcards(currentTarget);
-                lambdaType = types.findDescriptorType(currentTarget);
-            } else {
-                currentTarget = Type.recoveryType;
-                lambdaType = fallbackDescriptorType(that);
+            TargetInfo targetInfo = getTargetInfo(that, resultInfo, explicitParamTypes);
+            Type currentTarget = targetInfo.target;
+            Type lambdaType = targetInfo.descriptor;
+
+            if (currentTarget.isErroneous()) {
+                result = that.type = currentTarget;
+                return;
             }
 
             setFunctionalInfo(localEnv, that, pt(), lambdaType, currentTarget, resultInfo.checkContext);
@@ -2409,15 +2446,8 @@
             //with the target-type, it will be recovered anyway in Attr.checkId
             needsRecovery = false;
 
-            FunctionalReturnContext funcContext = that.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
-                    new ExpressionLambdaReturnContext((JCExpression)that.getBody(), resultInfo.checkContext) :
-                    new FunctionalReturnContext(resultInfo.checkContext);
-
-            ResultInfo bodyResultInfo = lambdaType.getReturnType() == Type.recoveryType ?
-                recoveryInfo :
-                new ResultInfo(KindSelector.VAL,
-                               lambdaType.getReturnType(), funcContext);
-            localEnv.info.returnResult = bodyResultInfo;
+            ResultInfo bodyResultInfo = localEnv.info.returnResult =
+                    lambdaBodyResult(that, lambdaType, resultInfo);
 
             if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
                 attribTree(that.getBody(), localEnv, bodyResultInfo);
@@ -2467,6 +2497,44 @@
         }
     }
     //where
+        class TargetInfo {
+            Type target;
+            Type descriptor;
+
+            public TargetInfo(Type target, Type descriptor) {
+                this.target = target;
+                this.descriptor = descriptor;
+            }
+        }
+
+        TargetInfo getTargetInfo(JCPolyExpression that, ResultInfo resultInfo, List<Type> explicitParamTypes) {
+            Type lambdaType;
+            Type currentTarget = resultInfo.pt;
+            if (resultInfo.pt != Type.recoveryType) {
+                /* We need to adjust the target. If the target is an
+                 * intersection type, for example: SAM & I1 & I2 ...
+                 * the target will be updated to SAM
+                 */
+                currentTarget = targetChecker.visit(currentTarget, that);
+                if (explicitParamTypes != null) {
+                    currentTarget = infer.instantiateFunctionalInterface(that,
+                            currentTarget, explicitParamTypes, resultInfo.checkContext);
+                }
+                currentTarget = types.removeWildcards(currentTarget);
+                lambdaType = types.findDescriptorType(currentTarget);
+            } else {
+                currentTarget = Type.recoveryType;
+                lambdaType = fallbackDescriptorType(that);
+            }
+            if (that.hasTag(LAMBDA) && lambdaType.hasTag(FORALL)) {
+                //lambda expression target desc cannot be a generic method
+                resultInfo.checkContext.report(that, diags.fragment("invalid.generic.lambda.target",
+                        lambdaType, kindName(currentTarget.tsym), currentTarget.tsym));
+                currentTarget = types.createErrorType(pt());
+            }
+            return new TargetInfo(currentTarget, lambdaType);
+        }
+
         void preFlow(JCLambda tree) {
             new PostAttrAnalyzer() {
                 @Override
@@ -2612,13 +2680,24 @@
             }
         }
 
+        ResultInfo lambdaBodyResult(JCLambda that, Type descriptor, ResultInfo resultInfo) {
+            FunctionalReturnContext funcContext = that.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
+                    new ExpressionLambdaReturnContext((JCExpression)that.getBody(), resultInfo.checkContext) :
+                    new FunctionalReturnContext(resultInfo.checkContext);
+
+            return descriptor.getReturnType() == Type.recoveryType ?
+                    recoveryInfo :
+                    new ResultInfo(KindSelector.VAL,
+                            descriptor.getReturnType(), funcContext);
+        }
+
         /**
         * Lambda compatibility. Check that given return types, thrown types, parameter types
         * are compatible with the expected functional interface descriptor. This means that:
         * (i) parameter types must be identical to those of the target descriptor; (ii) return
         * types must be compatible with the return type of the expected descriptor.
         */
-        private void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext) {
+        void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext) {
             Type returnType = checkContext.inferenceContext().asUndetVar(descriptor.getReturnType());
 
             //return values have already been checked - but if lambda has no return
@@ -2746,18 +2825,12 @@
                 typeargtypes = attribTypes(that.typeargs, localEnv);
             }
 
-            Type desc;
-            Type currentTarget = pt();
             boolean isTargetSerializable =
                     resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK &&
-                    isSerializable(currentTarget);
-            if (currentTarget != Type.recoveryType) {
-                currentTarget = types.removeWildcards(targetChecker.visit(currentTarget, that));
-                desc = types.findDescriptorType(currentTarget);
-            } else {
-                currentTarget = Type.recoveryType;
-                desc = fallbackDescriptorType(that);
-            }
+                    isSerializable(pt());
+            TargetInfo targetInfo = getTargetInfo(that, resultInfo, null);
+            Type currentTarget = targetInfo.target;
+            Type desc = targetInfo.descriptor;
 
             setFunctionalInfo(localEnv, that, pt(), desc, currentTarget, resultInfo.checkContext);
             List<Type> argtypes = desc.getParameterTypes();
@@ -3279,7 +3352,7 @@
         }
 
         // Attribute the qualifier expression, and determine its symbol (if any).
-        Type site = attribTree(tree.selected, env, new ResultInfo(skind, Infer.anyPoly));
+        Type site = attribTree(tree.selected, env, new ResultInfo(skind, Type.noType));
         if (!pkind().contains(KindSelector.TYP_PCK))
             site = capture(site); // Capture field access
 
@@ -3884,8 +3957,15 @@
                        syms.methodClass);
             }
 
-            return chk.checkMethod(owntype, sym, env, argtrees, argtypes, env.info.lastResolveVarargs(),
-                    resultInfo.checkContext.inferenceContext());
+            PolyKind pkind = (sym.type.hasTag(FORALL) &&
+                 sym.type.getReturnType().containsAny(((ForAll)sym.type).tvars)) ?
+                 PolyKind.POLY : PolyKind.STANDALONE;
+            TreeInfo.setPolyKind(env.tree, pkind);
+
+            return (resultInfo.pt == Infer.anyPoly) ?
+                    owntype :
+                    chk.checkMethod(owntype, sym, env, argtrees, argtypes, env.info.lastResolveVarargs(),
+                            resultInfo.checkContext.inferenceContext());
         } catch (Infer.InferenceException ex) {
             //invalid target type - propagate exception outwards or report error
             //depending on the current check context
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Mon Sep 14 11:26:14 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Sep 15 13:43:44 2015 +0100
@@ -49,7 +49,6 @@
 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
 import com.sun.tools.javac.comp.Infer.FreeTypeListener;
 import com.sun.tools.javac.tree.JCTree.*;
-import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Flags.ANNOTATION;
@@ -976,10 +975,6 @@
                 TreeInfo.setVarargsElement(env.tree, types.elemtype(argtype));
             }
          }
-         PolyKind pkind = (sym.type.hasTag(FORALL) &&
-                 sym.type.getReturnType().containsAny(((ForAll)sym.type).tvars)) ?
-                 PolyKind.POLY : PolyKind.STANDALONE;
-         TreeInfo.setPolyKind(env.tree, pkind);
          return owntype;
     }
     //where
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Mon Sep 14 11:26:14 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Tue Sep 15 13:43:44 2015 +0100
@@ -29,6 +29,7 @@
 import com.sun.source.tree.NewClassTree;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Type.TypeMapping;
+import com.sun.tools.javac.comp.ArgumentAttr.CachePolicy;
 import com.sun.tools.javac.comp.Resolve.ResolveError;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.tree.*;
@@ -36,7 +37,6 @@
 import com.sun.tools.javac.util.DefinedBy.Api;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.comp.Attr.ResultInfo;
 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
 import com.sun.tools.javac.tree.JCTree.*;
@@ -55,8 +55,6 @@
 
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
-import static com.sun.tools.javac.code.Kinds.*;
-import static com.sun.tools.javac.code.Kinds.Kind.*;
 
 /**
  * This is an helper class that is used to perform deferred type-analysis.
@@ -73,6 +71,7 @@
     protected static final Context.Key<DeferredAttr> deferredAttrKey = new Context.Key<>();
 
     final Attr attr;
+    final ArgumentAttr argumentAttr;
     final Check chk;
     final JCDiagnostic.Factory diags;
     final Enter enter;
@@ -98,6 +97,7 @@
     protected DeferredAttr(Context context) {
         context.put(deferredAttrKey, this);
         attr = Attr.instance(context);
+        argumentAttr = ArgumentAttr.instance(context);
         chk = Check.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
         enter = Enter.instance(context);
@@ -255,6 +255,15 @@
             return e != null ? e.speculativeTree.type : Type.noType;
         }
 
+        JCTree speculativeTree(DeferredAttrContext deferredAttrContext) {
+            DeferredType.SpeculativeCache.Entry e = speculativeCache.get(deferredAttrContext.msym, deferredAttrContext.phase);
+            return e != null ? e.speculativeTree : stuckTree;
+        }
+
+        DeferredTypeCompleter completer() {
+            return basicCompleter;
+        }
+
         /**
          * Check a deferred type against a potential target-type. Depending on
          * the current attribution mode, a normal vs. speculative attribution
@@ -272,7 +281,7 @@
             } else {
                 deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
             }
-            return check(resultInfo, deferredStuckPolicy, basicCompleter);
+            return check(resultInfo, deferredStuckPolicy, completer());
         }
 
         private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy,
@@ -389,6 +398,42 @@
     }
 
     /**
+     * Performs speculative attribution of a lambda body and returns the speculative lambda tree,
+     * in the absence of a target-type. Since {@link Attr#visitLambda(JCLambda)} cannot type-check
+     * lambda bodies w/o a suitable target-type, this routine 'unrolls' the lambda by turning it
+     * into a regular block, speculatively type-checks the block and then puts back the pieces.
+     */
+    JCLambda attribSpeculativeLambda(JCLambda that, Env<AttrContext> env, ResultInfo resultInfo) {
+        ListBuffer<JCStatement> stats = new ListBuffer<>();
+        stats.addAll(that.params);
+        if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
+            stats.add(make.Return((JCExpression)that.body));
+        } else {
+            stats.add((JCBlock)that.body);
+        }
+        JCBlock lambdaBlock = make.Block(0, stats.toList());
+        Env<AttrContext> localEnv = attr.lambdaEnv(that, env);
+        try {
+            localEnv.info.returnResult = resultInfo;
+            JCBlock speculativeTree = (JCBlock)attribSpeculative(lambdaBlock, localEnv, resultInfo);
+            List<JCVariableDecl> args = speculativeTree.getStatements().stream()
+                    .filter(s -> s.hasTag(Tag.VARDEF))
+                    .map(t -> (JCVariableDecl)t)
+                    .collect(List.collector());
+            JCTree lambdaBody = speculativeTree.getStatements().last();
+            if (lambdaBody.hasTag(Tag.RETURN)) {
+                lambdaBody = ((JCReturn)lambdaBody).expr;
+            }
+            JCLambda speculativeLambda = make.Lambda(args, lambdaBody);
+            attr.preFlow(speculativeLambda);
+            flow.analyzeLambda(env, speculativeLambda, make, false);
+            return speculativeLambda;
+        } finally {
+            localEnv.info.scope.leave();
+        }
+    }
+
+    /**
      * Routine that performs speculative type-checking; the input AST node is
      * cloned (to avoid side-effects cause by Attr) and compiler state is
      * restored after type-checking. All diagnostics (but critical ones) are
@@ -572,7 +617,7 @@
             }
         }
 
-        private boolean insideOverloadPhase() {
+        public boolean insideOverloadPhase() {
             DeferredAttrContext dac = this;
             if (dac == emptyDeferredAttrContext) {
                 return false;
@@ -731,56 +776,16 @@
             }
 
             boolean canLambdaBodyCompleteNormally(JCLambda tree) {
-                JCLambda newTree = new TreeCopier<>(make).copy(tree);
-                /* attr.lambdaEnv will create a meaningful env for the
-                 * lambda expression. This is specially useful when the
-                 * lambda is used as the init of a field. But we need to
-                 * remove any added symbol.
-                 */
-                Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env);
+                List<JCVariableDecl> oldParams = tree.params;
+                CachePolicy prevPolicy = argumentAttr.withCachePolicy(CachePolicy.NO_CACHE);
                 try {
-                    List<JCVariableDecl> tmpParams = newTree.params;
-                    while (tmpParams.nonEmpty()) {
-                        tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType);
-                        tmpParams = tmpParams.tail;
-                    }
-
-                    attr.attribStats(newTree.params, localEnv);
-
-                    /* set pt to Type.noType to avoid generating any bound
-                     * which may happen if lambda's return type is an
-                     * inference variable
-                     */
-                    Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(KindSelector.VAL, Type.noType);
-                    localEnv.info.returnResult = bodyResultInfo;
-
-                    // discard any log output
-                    Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
-                    try {
-                        JCBlock body = (JCBlock)newTree.body;
-                        /* we need to attribute the lambda body before
-                         * doing the aliveness analysis. This is because
-                         * constant folding occurs during attribution
-                         * and the reachability of some statements depends
-                         * on constant values, for example:
-                         *
-                         *     while (true) {...}
-                         */
-                        attr.attribStats(body.stats, localEnv);
-
-                        attr.preFlow(newTree);
-                        /* make an aliveness / reachability analysis of the lambda
-                         * to determine if it can complete normally
-                         */
-                        flow.analyzeLambda(localEnv, newTree, make, true);
-                    } finally {
-                        log.popDiagnosticHandler(diagHandler);
-                    }
-                    return newTree.canCompleteNormally;
+                    tree.params = tree.params.stream()
+                            .map(vd -> make.VarDef(vd.mods, vd.name, make.Erroneous(), null))
+                            .collect(List.collector());
+                    return attribSpeculativeLambda(tree, env, attr.unknownExprInfo).canCompleteNormally;
                 } finally {
-                    JCBlock body = (JCBlock)newTree.body;
-                    unenterScanner.scan(body.stats);
-                    localEnv.info.scope.leave();
+                    argumentAttr.withCachePolicy(prevPolicy);
+                    tree.params = oldParams;
                 }
             }
 
@@ -951,7 +956,7 @@
      * A special tree scanner that would only visit portions of a given tree.
      * The set of nodes visited by the scanner can be customized at construction-time.
      */
-    abstract static class FilterScanner extends TreeScanner {
+    abstract static class FilterScanner extends com.sun.tools.javac.tree.TreeScanner {
 
         final Filter<JCTree> treeFilter;
 
@@ -1148,330 +1153,4 @@
             }
         }
     }
-
-    /**
-     * Does the argument expression {@code expr} need speculative type-checking?
-     */
-    boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
-        DeferredChecker dc = new DeferredChecker(env);
-        dc.scan(expr);
-        return dc.result.isPoly();
-    }
-
-    /**
-     * The kind of an argument expression. This is used by the analysis that
-     * determines as to whether speculative attribution is necessary.
-     */
-    enum ArgumentExpressionKind {
-
-        /** kind that denotes poly argument expression */
-        POLY,
-        /** kind that denotes a standalone expression */
-        NO_POLY,
-        /** kind that denotes a primitive/boxed standalone expression */
-        PRIMITIVE;
-
-        /**
-         * Does this kind denote a poly argument expression
-         */
-        public final boolean isPoly() {
-            return this == POLY;
-        }
-
-        /**
-         * Does this kind denote a primitive standalone expression
-         */
-        public final boolean isPrimitive() {
-            return this == PRIMITIVE;
-        }
-
-        /**
-         * Compute the kind of a standalone expression of a given type
-         */
-        static ArgumentExpressionKind standaloneKind(Type type, Types types) {
-            return types.unboxedTypeOrType(type).isPrimitive() ?
-                    ArgumentExpressionKind.PRIMITIVE :
-                    ArgumentExpressionKind.NO_POLY;
-        }
-
-        /**
-         * Compute the kind of a method argument expression given its symbol
-         */
-        static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
-            Type restype = sym.type.getReturnType();
-            if (sym.type.hasTag(FORALL) &&
-                    restype.containsAny(((ForAll)sym.type).tvars)) {
-                return ArgumentExpressionKind.POLY;
-            } else {
-                return ArgumentExpressionKind.standaloneKind(restype, types);
-            }
-        }
-    }
-
-    /**
-     * Tree scanner used for checking as to whether an argument expression
-     * requires speculative attribution
-     */
-    final class DeferredChecker extends FilterScanner {
-
-        Env<AttrContext> env;
-        ArgumentExpressionKind result;
-
-        public DeferredChecker(Env<AttrContext> env) {
-            super(deferredCheckerTags);
-            this.env = env;
-        }
-
-        @Override
-        public void visitLambda(JCLambda tree) {
-            //a lambda is always a poly expression
-            result = ArgumentExpressionKind.POLY;
-        }
-
-        @Override
-        public void visitReference(JCMemberReference tree) {
-            //perform arity-based check
-            Env<AttrContext> localEnv = env.dup(tree);
-            JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
-                    attr.memberReferenceQualifierResult(tree));
-            JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
-            mref2.expr = exprTree;
-            Symbol res =
-                    rs.getMemberReference(tree, localEnv, mref2,
-                        exprTree.type, tree.name);
-            tree.sym = res;
-            if (res.kind.isResolutionTargetError() ||
-                    res.type != null && res.type.hasTag(FORALL) ||
-                    (res.flags() & Flags.VARARGS) != 0 ||
-                    (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
-                    exprTree.type.isRaw())) {
-                tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
-            } else {
-                tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
-            }
-            //a method reference is always a poly expression
-            result = ArgumentExpressionKind.POLY;
-        }
-
-        @Override
-        public void visitTypeCast(JCTypeCast tree) {
-            //a cast is always a standalone expression
-            result = ArgumentExpressionKind.NO_POLY;
-        }
-
-        @Override
-        public void visitConditional(JCConditional tree) {
-            scan(tree.truepart);
-            if (!result.isPrimitive()) {
-                result = ArgumentExpressionKind.POLY;
-                return;
-            }
-            scan(tree.falsepart);
-            result = reduce(ArgumentExpressionKind.PRIMITIVE).isPrimitive() ?
-                    ArgumentExpressionKind.PRIMITIVE :
-                    ArgumentExpressionKind.POLY;
-
-        }
-
-        @Override
-        public void visitNewClass(JCNewClass tree) {
-            result = TreeInfo.isDiamond(tree) ?
-                    ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
-        }
-
-        @Override
-        public void visitApply(JCMethodInvocation tree) {
-            Name name = TreeInfo.name(tree.meth);
-
-            //fast path
-            if (tree.typeargs.nonEmpty() ||
-                    name == name.table.names._this ||
-                    name == name.table.names._super) {
-                result = ArgumentExpressionKind.NO_POLY;
-                return;
-            }
-
-            //slow path
-            Symbol sym = quicklyResolveMethod(env, tree);
-
-            if (sym == null) {
-                result = ArgumentExpressionKind.POLY;
-                return;
-            }
-
-            result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE,
-                    argumentKindAnalyzer);
-        }
-        //where
-            private boolean isSimpleReceiver(JCTree rec) {
-                switch (rec.getTag()) {
-                    case IDENT:
-                        return true;
-                    case SELECT:
-                        return isSimpleReceiver(((JCFieldAccess)rec).selected);
-                    case TYPEAPPLY:
-                    case TYPEARRAY:
-                        return true;
-                    case ANNOTATED_TYPE:
-                        return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
-                    case APPLY:
-                        return true;
-                    case NEWCLASS:
-                        JCNewClass nc = (JCNewClass) rec;
-                        return nc.encl == null && nc.def == null && !TreeInfo.isDiamond(nc);
-                    default:
-                        return false;
-                }
-            }
-            private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
-                return argumentKindAnalyzer.reduce(result, kind);
-            }
-            MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer =
-                    new MethodAnalyzer<ArgumentExpressionKind>() {
-                @Override
-                public ArgumentExpressionKind process(MethodSymbol ms) {
-                    return ArgumentExpressionKind.methodKind(ms, types);
-                }
-                @Override
-                public ArgumentExpressionKind reduce(ArgumentExpressionKind kind1,
-                                                     ArgumentExpressionKind kind2) {
-                    switch (kind1) {
-                        case PRIMITIVE: return kind2;
-                        case NO_POLY: return kind2.isPoly() ? kind2 : kind1;
-                        case POLY: return kind1;
-                        default:
-                            Assert.error();
-                            return null;
-                    }
-                }
-                @Override
-                public boolean shouldStop(ArgumentExpressionKind result) {
-                    return result.isPoly();
-                }
-            };
-
-        @Override
-        public void visitLiteral(JCLiteral tree) {
-            Type litType = attr.litType(tree.typetag);
-            result = ArgumentExpressionKind.standaloneKind(litType, types);
-        }
-
-        @Override
-        void skip(JCTree tree) {
-            result = ArgumentExpressionKind.NO_POLY;
-        }
-
-        private Symbol quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree) {
-            final JCExpression rec = tree.meth.hasTag(SELECT) ?
-                    ((JCFieldAccess)tree.meth).selected :
-                    null;
-
-            if (rec != null && !isSimpleReceiver(rec)) {
-                return null;
-            }
-
-            Type site;
-
-            if (rec != null) {
-                switch (rec.getTag()) {
-                    case APPLY:
-                        Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec);
-                        if (recSym == null)
-                            return null;
-                        Symbol resolvedReturnType =
-                                analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer);
-                        if (resolvedReturnType == null)
-                            return null;
-                        site = resolvedReturnType.type;
-                        break;
-                    case NEWCLASS:
-                        JCNewClass nc = (JCNewClass) rec;
-                        site = attribSpeculative(nc.clazz, env, attr.unknownTypeExprInfo).type;
-                        break;
-                    default:
-                        site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type;
-                        break;
-                }
-            } else {
-                site = env.enclClass.sym.type;
-            }
-
-            site = types.skipTypeVars(site, true);
-
-            List<Type> args = rs.dummyArgs(tree.args.length());
-            Name name = TreeInfo.name(tree.meth);
-
-            Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
-                @Override
-                Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
-                    return rec == null ?
-                        rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
-                        rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired());
-                }
-                @Override
-                Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
-                    return sym;
-                }
-            };
-
-            return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
-        }
-        //where:
-            MethodAnalyzer<Symbol> returnSymbolAnalyzer = new MethodAnalyzer<Symbol>() {
-                @Override
-                public Symbol process(MethodSymbol ms) {
-                    ArgumentExpressionKind kind = ArgumentExpressionKind.methodKind(ms, types);
-                    if (kind == ArgumentExpressionKind.POLY || ms.getReturnType().hasTag(TYPEVAR))
-                        return null;
-                    return ms.getReturnType().tsym;
-                }
-                @Override
-                public Symbol reduce(Symbol s1, Symbol s2) {
-                    return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null;
-                }
-                @Override
-                public boolean shouldStop(Symbol result) {
-                    return result == null;
-                }
-            };
-
-        /**
-         * Process the result of Resolve.lookupMethod. If sym is a method symbol, the result of
-         * MethodAnalyzer.process is returned. If sym is an ambiguous symbol, all the candidate
-         * methods are inspected one by one, using MethodAnalyzer.process. The outcomes are
-         * reduced using MethodAnalyzer.reduce (using defaultValue as the first value over which
-         * the reduction runs). MethodAnalyzer.shouldStop can be used to stop the inspection early.
-         */
-        <E> E analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer) {
-            switch (sym.kind) {
-                case MTH:
-                    return analyzer.process((MethodSymbol) sym);
-                case AMBIGUOUS:
-                    Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
-                    E res = defaultValue;
-                    for (Symbol s : err.ambiguousSyms) {
-                        if (s.kind == MTH) {
-                            res = analyzer.reduce(res, analyzer.process((MethodSymbol) s));
-                            if (analyzer.shouldStop(res))
-                                return res;
-                        }
-                    }
-                    return res;
-                default:
-                    return defaultValue;
-            }
-        }
-    }
-
-    /** Analyzer for methods - used by analyzeCandidateMethods. */
-    interface MethodAnalyzer<E> {
-        E process(MethodSymbol ms);
-        E reduce(E e1, E e2);
-        boolean shouldStop(E result);
-    }
-
-    //where
-    private EnumSet<JCTree.Tag> deferredCheckerTags =
-            EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
-                    CONDEXPR, NEWCLASS, APPLY, LITERAL);
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Mon Sep 14 11:26:14 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Tue Sep 15 13:43:44 2015 +0100
@@ -37,6 +37,7 @@
 import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
 import com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph;
 import com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph.Node;
 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
@@ -179,7 +180,11 @@
 
             resolveContext.methodCheck.argumentsAcceptable(env, deferredAttrContext,   //B2
                     argtypes, mt.getParameterTypes(), warn);
-            if (allowGraphInference &&
+
+            if (allowGraphInference && resultInfo != null && resultInfo.pt == anyPoly) {
+                //we are inside method attribution - just return a partially inferred type
+                return new PartiallyInferredMethodType(mt, inferenceContext, env, warn);
+            } else if (allowGraphInference &&
                     resultInfo != null &&
                     !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
                 //inject return constraints earlier
@@ -238,6 +243,73 @@
         }
     }
 
+    /**
+     * A partially infered method/constructor type; such a type can be checked multiple times
+     * against different targets.
+     */
+    public class PartiallyInferredMethodType extends MethodType {
+        public PartiallyInferredMethodType(MethodType mtype, InferenceContext inferenceContext, Env<AttrContext> env, Warner warn) {
+            super(mtype.getParameterTypes(), mtype.getReturnType(), mtype.getThrownTypes(), mtype.tsym);
+            this.inferenceContext = inferenceContext;
+            this.env = env;
+            this.warn = warn;
+        }
+
+        /** The inference context. */
+        final InferenceContext inferenceContext;
+
+        /** The attribution environment. */
+        Env<AttrContext> env;
+
+        /** The warner. */
+        final Warner warn;
+
+        @Override
+        public boolean isPartial() {
+            return true;
+        }
+
+        /**
+         * Checks this type against a target; this means generating return type constraints, solve
+         * and then roll back the results (to avoid poolluting the context).
+         */
+        Type check(Attr.ResultInfo resultInfo) {
+            Warner noWarnings = new Warner(null);
+            inferenceException.clear();
+            List<Type> saved_undet = null;
+            try {
+                /** we need to save the inference context before generating target type constraints.
+                 *  This constraints may pollute the inference context and make it useless in case we
+                 *  need to use it several times: with several targets.
+                 */
+                saved_undet = inferenceContext.save();
+                if (allowGraphInference && !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
+                    //inject return constraints earlier
+                    checkWithinBounds(inferenceContext, noWarnings); //propagation
+                    Type res = generateReturnConstraints(env.tree, resultInfo,  //B3
+                        this, inferenceContext);
+
+                    if (resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
+                        //propagate inference context outwards and exit
+                        inferenceContext.dupTo(resultInfo.checkContext.inferenceContext(),
+                                resultInfo.checkContext.deferredAttrContext().insideOverloadPhase());
+                        return res;
+                    }
+                }
+                inferenceContext.solve(noWarnings);
+                return inferenceContext.asInstType(this).getReturnType();
+            } catch (InferenceException ex) {
+                resultInfo.checkContext.report(null, ex.getDiagnostic());
+                Assert.error(); //cannot get here (the above should throw)
+                return null;
+            } finally {
+                if (saved_undet != null) {
+                    inferenceContext.rollback(saved_undet);
+                }
+            }
+        }
+    }
+
     private void dumpGraphsIfNeeded(DiagnosticPosition pos, Symbol msym, Resolve.MethodResolutionContext rsContext) {
         int round = 0;
         try {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java	Mon Sep 14 11:26:14 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java	Tue Sep 15 13:43:44 2015 +0100
@@ -315,31 +315,46 @@
         return buf.toList();
     }
 
-    /**
-     * Restore the state of this inference context to the previous known checkpoint
-     */
+    /** Restore the state of this inference context to the previous known checkpoint.
+    *  Consider that the number of saved undetermined variables can be different to the current
+    *  amount. This is because new captured variables could have been added.
+    */
     void rollback(List<Type> saved_undet) {
-         Assert.check(saved_undet != null && saved_undet.length() == undetvars.length());
+        Assert.check(saved_undet != null);
         //restore bounds (note: we need to preserve the old instances)
-        for (Type t : undetvars) {
-            UndetVar uv = (UndetVar)t;
+        ListBuffer<Type> newUndetVars = new ListBuffer<>();
+        ListBuffer<Type> newInferenceVars = new ListBuffer<>();
+        while (saved_undet.nonEmpty() && undetvars.nonEmpty()) {
+            UndetVar uv = (UndetVar)undetvars.head;
             UndetVar uv_saved = (UndetVar)saved_undet.head;
-            for (InferenceBound ib : InferenceBound.values()) {
-                uv.setBounds(ib, uv_saved.getBounds(ib));
+            if (uv.qtype == uv_saved.qtype) {
+                for (InferenceBound ib : InferenceBound.values()) {
+                    uv.setBounds(ib, uv_saved.getBounds(ib));
+                }
+                uv.inst = uv_saved.inst;
+                undetvars = undetvars.tail;
+                saved_undet = saved_undet.tail;
+                newUndetVars.add(uv);
+                newInferenceVars.add(uv.qtype);
+            } else {
+                undetvars = undetvars.tail;
             }
-            uv.inst = uv_saved.inst;
-            saved_undet = saved_undet.tail;
         }
+        undetvars = newUndetVars.toList();
+        inferencevars = newInferenceVars.toList();
     }
 
     /**
      * Copy variable in this inference context to the given context
      */
     void dupTo(final InferenceContext that) {
-        that.inferencevars = that.inferencevars.appendList(
-                inferencevars.diff(that.inferencevars));
-        that.undetvars = that.undetvars.appendList(
-                undetvars.diff(that.undetvars));
+        dupTo(that, false);
+    }
+
+    void dupTo(final InferenceContext that, boolean clone) {
+        that.inferencevars = that.inferencevars.appendList(inferencevars.diff(that.inferencevars));
+        List<Type> undetsToPropagate = clone ? save() : undetvars;
+        that.undetvars = that.undetvars.appendList(undetsToPropagate.diff(that.undetvars)); //propagate cloned undet!!
         //set up listeners to notify original inference contexts as
         //propagated vars are inferred in new context
         for (Type t : inferencevars) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Sep 14 11:26:14 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Sep 15 13:43:44 2015 +0100
@@ -588,7 +588,8 @@
         MethodResolutionContext prevContext = currentResolutionContext;
         try {
             currentResolutionContext = new MethodResolutionContext();
-            currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK;
+            currentResolutionContext.attrMode = (resultInfo.pt == Infer.anyPoly) ?
+                    AttrMode.SPECULATIVE : DeferredAttr.AttrMode.CHECK;
             if (env.tree.hasTag(JCTree.Tag.REFERENCE)) {
                 //method/constructor references need special check class
                 //to handle inference variables in 'argtypes' (might happen
@@ -1032,6 +1033,11 @@
         protected ResultInfo dup(CheckContext newContext) {
             return new MethodResultInfo(pt, newContext);
         }
+
+        @Override
+        protected ResultInfo dup(Type newPt, CheckContext newContext) {
+            return new MethodResultInfo(newPt, newContext);
+        }
     }
 
     /**
@@ -1092,10 +1098,9 @@
                         unrelatedFunctionalInterfaces(found, req) &&
                         (actual != null && actual.getTag() == DEFERRED)) {
                     DeferredType dt = (DeferredType) actual;
-                    DeferredType.SpeculativeCache.Entry e =
-                            dt.speculativeCache.get(deferredAttrContext.msym, deferredAttrContext.phase);
-                    if (e != null && e.speculativeTree != deferredAttr.stuckTree) {
-                        return functionalInterfaceMostSpecific(found, req, e.speculativeTree);
+                    JCTree speculativeTree = dt.speculativeTree(deferredAttrContext);
+                    if (speculativeTree != deferredAttr.stuckTree) {
+                        return functionalInterfaceMostSpecific(found, req, speculativeTree);
                     }
                 }
                 return compatibleBySubtyping(found, req);
@@ -1147,8 +1152,8 @@
 
                 @Override
                 public void visitConditional(JCConditional tree) {
-                    scan(tree.truepart);
-                    scan(tree.falsepart);
+                    scan(asExpr(tree.truepart));
+                    scan(asExpr(tree.falsepart));
                 }
 
                 @Override
@@ -1180,6 +1185,11 @@
                 }
 
                 @Override
+                public void visitParens(JCParens tree) {
+                    scan(asExpr(tree.expr));
+                }
+
+                @Override
                 public void visitLambda(JCLambda tree) {
                     Type desc_t = types.findDescriptorType(t);
                     Type desc_s = types.findDescriptorType(s);
@@ -1214,7 +1224,7 @@
 
                 private List<JCExpression> lambdaResults(JCLambda lambda) {
                     if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
-                        return List.of((JCExpression) lambda.body);
+                        return List.of(asExpr((JCExpression) lambda.body));
                     } else {
                         final ListBuffer<JCExpression> buffer = new ListBuffer<>();
                         DeferredAttr.LambdaReturnScanner lambdaScanner =
@@ -1222,7 +1232,7 @@
                                     @Override
                                     public void visitReturn(JCReturn tree) {
                                         if (tree.expr != null) {
-                                            buffer.append(tree.expr);
+                                            buffer.append(asExpr(tree.expr));
                                         }
                                     }
                                 };
@@ -1230,6 +1240,16 @@
                         return buffer.toList();
                     }
                 }
+
+                private JCExpression asExpr(JCExpression expr) {
+                    if (expr.type.hasTag(DEFERRED)) {
+                        JCTree speculativeTree = ((DeferredType)expr.type).speculativeTree(deferredAttrContext);
+                        if (speculativeTree != deferredAttr.stuckTree) {
+                            expr = (JCExpression)speculativeTree;
+                        }
+                    }
+                    return expr;
+                }
             }
 
         }
--- a/langtools/test/tools/javac/generics/wildcards/neg/Readonly.out	Mon Sep 14 11:26:14 2015 +0100
+++ b/langtools/test/tools/javac/generics/wildcards/neg/Readonly.out	Tue Sep 15 13:43:44 2015 +0100
@@ -1,2 +1,2 @@
-Readonly.java:15:10: compiler.err.cant.apply.symbol: kindname.method, put, Err<compiler.misc.type.captureof: 1, ? extends java.lang.String>, Err<compiler.misc.type.captureof: 2, ? extends java.lang.String>, kindname.class, Err<T>, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: Err<compiler.misc.type.captureof: 2, ? extends java.lang.String>, Err<compiler.misc.type.captureof: 1, ? extends java.lang.String>))
+Readonly.java:15:10: compiler.err.cant.apply.symbol: kindname.method, put, Err<compiler.misc.type.captureof: 1, ? extends java.lang.String>, Err<compiler.misc.type.captureof: 2, ? extends java.lang.String>, kindname.class, Err<T>, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: Err<compiler.misc.type.captureof: 3, ? extends java.lang.String>, Err<compiler.misc.type.captureof: 1, ? extends java.lang.String>))
 1 error
--- a/langtools/test/tools/javac/lambda/8019480/T8019480.out	Mon Sep 14 11:26:14 2015 +0100
+++ b/langtools/test/tools/javac/lambda/8019480/T8019480.out	Tue Sep 15 13:43:44 2015 +0100
@@ -1,3 +1,3 @@
+T8019480.java:21:34: compiler.err.cant.apply.symbols: kindname.method, add, java.lang.Object,{(compiler.misc.inapplicable.method: kindname.method, java.util.Collection, add(U), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, U))),(compiler.misc.inapplicable.method: kindname.method, java.util.List, add(U), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, U))),(compiler.misc.inapplicable.method: kindname.method, java.util.List, add(int,U), (compiler.misc.arg.length.mismatch))}
 T8019480.java:21:46: compiler.err.report.access: clone(), protected, java.lang.Object
-T8019480.java:21:34: compiler.err.cant.apply.symbols: kindname.method, add, java.lang.Object,{(compiler.misc.inapplicable.method: kindname.method, java.util.Collection, add(U), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, U))),(compiler.misc.inapplicable.method: kindname.method, java.util.List, add(U), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, U))),(compiler.misc.inapplicable.method: kindname.method, java.util.List, add(int,U), (compiler.misc.arg.length.mismatch))}
 2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/speculative/InferStrict.java	Tue Sep 15 13:43:44 2015 +0100
@@ -0,0 +1,45 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 8078093
+  * @summary Exponential performance regression Java 8 compiler compared to Java 7 compiler
+  * @compile InferStrict.java
+  */
+import java.util.HashSet;
+import java.util.Set;
+
+class InferStrict {
+    public <T> Set<T> compute(Set<T> t) { return t; }
+    public <T> T join(Set<T> t1, Set<T> t2) { return null; }
+    public <T extends InferStrict> T compute() { return null; }
+    public void test() {
+        join(
+            compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(new HashSet<>()))))))))))))))))),
+            compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(compute(new HashSet<String>())))))))))))))))))
+        ).length();
+     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/speculative/InferWeak.java	Tue Sep 15 13:43:44 2015 +0100
@@ -0,0 +1,82 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 8078093
+  * @summary Exponential performance regression Java 8 compiler compared to Java 7 compiler
+  * @compile InferWeak.java
+  */
+class InferWeak {
+    private void test() {
+        GroupLayout l = new GroupLayout();
+        l.setHorizontalGroup(
+            l.createParallelGroup().addGroup(l.createParallelGroup().addGroup(
+            l.createParallelGroup().addGroup(l.createParallelGroup().addGroup(
+            l.createParallelGroup().addGroup(l.createParallelGroup().addGroup(
+            l.createParallelGroup().addGroup(l.createParallelGroup().addGroup(
+            l.createParallelGroup().addGroup(l.createParallelGroup().addGroup(
+            l.createParallelGroup().addGroup(l.createParallelGroup().addGroup(
+            l.createParallelGroup().addGroup(l.createParallelGroup().addGroup(
+            l.createParallelGroup().addGroup(l.createParallelGroup().addGroup(
+            l.createParallelGroup().addGroup(l.createParallelGroup().addGroup(
+            l.createParallelGroup().addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object())).addGap(1).addComponent(new Object()).addGap(1)
+            .addComponent(new Object()));
+    }
+
+    static class GroupLayout {
+        <T extends ParallelGroup> T createParallelGroup() {return null;}
+        <T extends ParallelGroup> T createParallelGroup(int i) {return null;}
+        <T extends ParallelGroup> T createParallelGroup(int i, int j) {return null;}
+        void setHorizontalGroup(ParallelGroup g) { }
+    }
+
+    static class ParallelGroup {
+        <T extends ParallelGroup> T addGroup(ParallelGroup g) { return null; }
+        <T extends ParallelGroup> T addGroup(int i, ParallelGroup g) { return null; }
+        <T extends ParallelGroup> T addGap(int i) { return null; }
+        <T extends ParallelGroup> T addGap(int i, int j) { return null; }
+        <T extends ParallelGroup> T addComponent(Object c) { return null; }
+        <T extends ParallelGroup> T addComponent(int i, Object c) { return null; }
+    }
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/speculative/NestedLambdaGenerics.java	Tue Sep 15 13:43:44 2015 +0100
@@ -0,0 +1,54 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 8078093
+  * @summary Exponential performance regression Java 8 compiler compared to Java 7 compiler
+  * @compile NestedLambdaGenerics.java
+  */
+import java.util.concurrent.Callable;
+
+class NestedLambdaGenerics {
+    void test() {
+        m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null,
+                () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null,
+                () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null,
+                () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null,
+                () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null,
+                (Callable<String>)null)))))))))))))))))))))))))))))));
+    }
+    static class A0 { }
+    static class A1 { }
+    static class A2 { }
+    static class A3 { }
+    static class A4 { }
+    <Z extends A0> Z m(A0 t, Callable<Z> ct) { return null; }
+    <Z extends A1> Z m(A1 t, Callable<Z> ct) { return null; }
+    <Z extends A2> Z m(A2 t, Callable<Z> ct) { return null; }
+    <Z extends A3> Z m(A3 t, Callable<Z> ct) { return null; }
+    <Z extends A4> Z m(A4 t, Callable<Z> ct) { return null; }
+    <Z> Z m(Object o, Callable<Z> co) { return null; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/speculative/NestedLambdaNoGenerics.java	Tue Sep 15 13:43:44 2015 +0100
@@ -0,0 +1,54 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 8078093
+  * @summary Exponential performance regression Java 8 compiler compared to Java 7 compiler
+  * @compile NestedLambdaNoGenerics.java
+  */
+import java.util.concurrent.Callable;
+
+class NestedLambdaNoGenerics {
+    void test() {
+        m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null,
+                () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null,
+                () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null,
+                () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null,
+                () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null, () -> m(null,
+                (Callable<String>)null)))))))))))))))))))))))))))))));
+    }
+    static class A0 { }
+    static class A1 { }
+    static class A2 { }
+    static class A3 { }
+    static class A4 { }
+    String m(A0 t, Callable<A0> ct) { return ""; }
+    String m(A1 t, Callable<A1> ct) { return ""; }
+    String m(A2 t, Callable<A2> ct) { return ""; }
+    String m(A3 t, Callable<A3> ct) { return ""; }
+    String m(A4 t, Callable<A4> ct) { return ""; }
+    String m(Object o, Callable<String> co) { return ""; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/speculative/T8055984.java	Tue Sep 15 13:43:44 2015 +0100
@@ -0,0 +1,62 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 8078093 8055894
+ * @summary Exponential performance regression Java 8 compiler compared to Java 7 compiler
+ * @compile T8055984.java
+ */
+
+class T8055984 {
+    static class C<U> {
+        U fu;
+
+        C() { }
+
+        C(C<U> other) {
+            this.fu = other.fu;
+        }
+
+        C(U fu) {
+            this.fu = fu;
+        }
+    }
+
+    static <U> C<U> m(C<U> src) { return new C<U>(src); }
+
+    static void test() {
+        C<String> c2 = m(new C<>(m(new C<>() )) );
+        C<String> c3 = m(new C<>(m(new C<>(m(new C<>() )) )) );
+        C<String> c4 = m(new C<>(m(new C<>(m(new C<>(m(new C<>() )) )) )) );
+        C<String> c5 = m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>() )) )) )) )) );
+        C<String> c6 = m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>() )) )) )) )) )) );
+        C<String> c7 = m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>() )) )) )) )) )) )) );
+        C<String> c8 = m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>() )) )) )) )) )) )) )) );
+        C<String> c9 = m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>() )) )) )) )) )) )) )) )) );
+        C<String> c10 = m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>(m(new C<>())))))))))))))))))));
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/speculative/T8077247.java	Tue Sep 15 13:43:44 2015 +0100
@@ -0,0 +1,77 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 8078093 8077247
+ * @summary Exponential performance regression Java 8 compiler compared to Java 7 compiler
+ * @compile T8077247.java
+ */
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+class T8077247 {
+    public static void test() {
+        int x = add(add(add(add(add(add(add(add(add(add(1, 2), 3), 4), 5), 6), 7), 8), 9), 10), 11);
+    }
+
+    public static int add(int x, int y) {
+        long rslt = (long)x + (long)y;
+        if (Integer.MIN_VALUE <= rslt && rslt <= Integer.MAX_VALUE) {
+            return (int)rslt;
+        }
+
+        String msg = String.format("Integer overflow: %d + %d.", x, y);
+        throw new IllegalArgumentException(msg);
+    }
+
+    public static double add(double x, double y) {
+        double rslt = x + y;
+        if (Double.isInfinite(rslt)) {
+            String msg = String.format("Real overflow: %s + %s.", x, y);
+            throw new IllegalArgumentException(msg);
+        }
+        return (rslt == -0.0) ? 0.0 : rslt;
+    }
+
+    public static <T> List<T> add(List<T> x, List<T> y) {
+        List<T> rslt = new ArrayList<>(x.size() + y.size());
+        rslt.addAll(x);
+        rslt.addAll(y);
+        return rslt;
+    }
+
+    public static String add(String x, String y) {
+        return x + y;
+    }
+
+    public static <K, V> Map<K, V> add(Map<K, V> x, Map<K, V> y) {
+        Map<K, V> rslt = new HashMap<>(x);
+        rslt.putAll(y);
+        return rslt;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/speculative/T8078093.java	Tue Sep 15 13:43:44 2015 +0100
@@ -0,0 +1,50 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 8078093
+ * @summary Exponential performance regression Java 8 compiler compared to Java 7 compiler
+ * @compile T8078093.java
+ */
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+class T8078093 {
+    public static void test() {
+        Map<Integer, String> a = x(x(x(x(x(x(x(x(x(x(x(x(
+                                    new LinkedHashMap<Integer, String>(),
+                                    1, "a"), 2, "b"), 3, "c"), 4, "d"),
+                                    5, "e"), 6, "f"), 7, "g"), 8, "h"),
+                                    9, "i"), 10, "j"), 11, "k"), 12, "l");
+    }
+
+    @SuppressWarnings("unused")
+    public static <K, V> Map<K, V> x(Map<K, V> m, K k, V v) {
+        // Replaced actual code by dummy implementation.
+        return null;
+    }
+}