changeset 47341:e586e8f7b8ce condy-folding

javac rewrite of the condy folding feature
author vromero
date Fri, 29 Sep 2017 14:47:23 -0700
parents cf497ae988ca
children 09ab710722ce
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstFold.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstablesVisitor.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/SpecialConstantUtils.java test/langtools/tools/javac/specialConstantFolding/IndyNegativeTest01.out
diffstat 29 files changed, 1520 insertions(+), 152 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Fri Sep 29 14:47:23 2017 -0700
@@ -226,6 +226,9 @@
     public boolean allowUnderscoreIdentifier() {
         return compareTo(JDK1_8) <= 0;
     }
+    public boolean allowCondyForLambda() {
+        return compareTo(JDK1_10) >= 0;
+    }
     public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
     public boolean allowLocalVariableTypeInference() { return compareTo(JDK1_10) >= 0; }
     public static SourceVersion toSourceVersion(Source source) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Sep 29 14:47:23 2017 -0700
@@ -48,7 +48,6 @@
 import javax.tools.JavaFileObject;
 
 import com.sun.tools.javac.code.ClassFinder.BadEnclosingMethodAttr;
-import com.sun.tools.javac.code.Directive.RequiresFlag;
 import com.sun.tools.javac.code.Kinds.Kind;
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.code.Scope.WriteableScope;
@@ -68,7 +67,6 @@
 import static com.sun.tools.javac.code.Kinds.*;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
-import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.FIRSTASGOP;
 import static com.sun.tools.javac.code.TypeTag.CLASS;
 import static com.sun.tools.javac.code.TypeTag.FORALL;
 import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
@@ -2003,6 +2001,22 @@
         public List<Type> getThrownTypes() {
             return asType().getThrownTypes();
         }
+
+        public boolean isIntrinsicsLDC() { return false; }
+    }
+
+    public static class IntrinsicsLDCMethodSymbol extends MethodSymbol {
+        private Object constant;
+
+        public IntrinsicsLDCMethodSymbol(long flags, Name name, Type type, Symbol owner, Object constant) {
+            super(flags, name, type, owner);
+            this.constant = constant;
+        }
+
+        public Object getConstant() { return constant; }
+
+        @Override
+        public boolean isIntrinsicsLDC() { return true; }
     }
 
     /** A class for invokedynamic method calls.
@@ -2010,7 +2024,7 @@
     public static class DynamicMethodSymbol extends MethodSymbol {
 
         public Object[] staticArgs;
-        public Symbol bsm;
+        public MethodSymbol bsm;
         public int bsmKind;
 
         public DynamicMethodSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) {
@@ -2026,6 +2040,31 @@
         }
     }
 
+    /** A class for condy.
+     */
+    public static class DynamicFieldSymbol extends Symbol {
+
+        public Object[] staticArgs;
+        public MethodSymbol bsm;
+        public int bsmKind;
+
+        public DynamicFieldSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) {
+            super(Kind.VAR, 0, name, type, owner);
+            this.bsm = bsm;
+            this.bsmKind = bsmKind;
+            this.staticArgs = staticArgs;
+        }
+
+        public boolean isDynamic() {
+            return true;
+        }
+
+        @Override
+        public <R, P> R accept(ElementVisitor<R, P> v, P p) {
+            return v.visit(this, p);
+        }
+    }
+
     /** A class for predefined operators.
      */
     public static class OperatorSymbol extends MethodSymbol {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Fri Sep 29 14:47:23 2017 -0700
@@ -169,8 +169,12 @@
     public final Type serializedLambdaType;
     public final Type varHandleType;
     public final Type methodHandleType;
-    public final Type methodHandleLookupType;
+    public final Type methodHandlesLookupType;
+    public final Type constablesType;
+    public final Type dynamicConstantRefType;
+    public final Type intrinsicsType;
     public final Type methodTypeType;
+    public final Type trackableConstantType;
     public final Type nativeHeaderType;
     public final Type throwableType;
     public final Type errorType;
@@ -493,8 +497,12 @@
         serializedLambdaType = enterClass("java.lang.invoke.SerializedLambda");
         varHandleType = enterClass("java.lang.invoke.VarHandle");
         methodHandleType = enterClass("java.lang.invoke.MethodHandle");
-        methodHandleLookupType = enterClass("java.lang.invoke.MethodHandles$Lookup");
+        methodHandlesLookupType = enterClass("java.lang.invoke.MethodHandles$Lookup");
+        constablesType = enterClass("java.lang.invoke.Constables");
+        dynamicConstantRefType = enterClass("java.lang.invoke.DynamicConstantRef");
+        intrinsicsType = enterClass("java.lang.invoke.Intrinsics");
         methodTypeType = enterClass("java.lang.invoke.MethodType");
+        trackableConstantType = enterClass("java.lang.annotation.TrackableConstant");
         errorType = enterClass("java.lang.Error");
         illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
         interruptedExceptionType = enterClass("java.lang.InterruptedException");
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Fri Sep 29 14:47:23 2017 -0700
@@ -482,9 +482,9 @@
     /**
      * The constant value of this type, converted to String
      */
-    public String stringValue() {
-        Object cv = Assert.checkNonNull(constValue());
-        return cv.toString();
+    public String stringValue(Object value) {
+        Assert.checkNonNull(value);
+        return value.toString();
     }
 
     /**
@@ -747,8 +747,8 @@
          * The constant value of this type, converted to String
          */
         @Override
-        public String stringValue() {
-            Object cv = Assert.checkNonNull(constValue());
+        public String stringValue(Object cv) {
+            Assert.checkNonNull(cv);
             if (tag == BOOLEAN) {
                 return ((Integer) cv).intValue() == 0 ? "false" : "true";
             }
@@ -2283,7 +2283,7 @@
         }
 
         @Override
-        public String stringValue() {
+        public String stringValue(Object value) {
             return "null";
         }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java	Fri Sep 29 14:47:23 2017 -0700
@@ -42,36 +42,36 @@
 public enum TypeTag {
     /** The tag of the basic type `byte'.
      */
-    BYTE(BYTE_CLASS, BYTE_SUPERCLASSES, true),
+    BYTE(BYTE_CLASS, BYTE_SUPERCLASSES, true, byte.class),
 
     /** The tag of the basic type `char'.
      */
-    CHAR(CHAR_CLASS, CHAR_SUPERCLASSES, true),
+    CHAR(CHAR_CLASS, CHAR_SUPERCLASSES, true, char.class),
 
     /** The tag of the basic type `short'.
      */
-    SHORT(SHORT_CLASS, SHORT_SUPERCLASSES, true),
+    SHORT(SHORT_CLASS, SHORT_SUPERCLASSES, true, short.class),
 
     /** The tag of the basic type `long'.
      */
-    LONG(LONG_CLASS, LONG_SUPERCLASSES, true),
+    LONG(LONG_CLASS, LONG_SUPERCLASSES, true, long.class),
 
     /** The tag of the basic type `float'.
      */
-    FLOAT(FLOAT_CLASS, FLOAT_SUPERCLASSES, true),
+    FLOAT(FLOAT_CLASS, FLOAT_SUPERCLASSES, true, float.class),
     /** The tag of the basic type `int'.
      */
-    INT(INT_CLASS, INT_SUPERCLASSES, true),
+    INT(INT_CLASS, INT_SUPERCLASSES, true, int.class),
     /** The tag of the basic type `double'.
      */
-    DOUBLE(DOUBLE_CLASS, DOUBLE_CLASS, true),
+    DOUBLE(DOUBLE_CLASS, DOUBLE_CLASS, true, double.class),
     /** The tag of the basic type `boolean'.
      */
-    BOOLEAN(0, 0, true),
+    BOOLEAN(0, 0, true, boolean.class),
 
     /** The tag of the type `void'.
      */
-    VOID,
+    VOID(0, 0, false, void.class),
 
     /** The tag of all class and interface types.
      */
@@ -138,15 +138,17 @@
     final int superClasses;
     final int numericClass;
     final boolean isPrimitive;
+    public final Class<?> theClass;
 
     private TypeTag() {
-        this(0, 0, false);
+        this(0, 0, false, null);
     }
 
-    private TypeTag(int numericClass, int superClasses, boolean isPrimitive) {
+    private TypeTag(int numericClass, int superClasses, boolean isPrimitive, Class<?> theClass) {
         this.superClasses = superClasses;
         this.numericClass = numericClass;
         this.isPrimitive = isPrimitive;
+        this.theClass = theClass;
     }
 
     public static class NumericClasses {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Fri Sep 29 14:47:23 2017 -0700
@@ -58,6 +58,7 @@
 import static com.sun.tools.javac.code.Type.*;
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.jvm.ClassFile.externalize;
+
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 
 /**
@@ -99,6 +100,8 @@
     private final FunctionDescriptorLookupError functionDescriptorLookupError;
 
     public final Warner noWarnings;
+    private final boolean doConstantFold;
+    private final SpecialConstantUtils specialConstUtils;
 
     // <editor-fold defaultstate="collapsed" desc="Instantiating">
     public static Types instance(Context context) {
@@ -123,6 +126,9 @@
         diags = JCDiagnostic.Factory.instance(context);
         functionDescriptorLookupError = new FunctionDescriptorLookupError();
         noWarnings = new Warner(null);
+        Options options = Options.instance(context);
+        doConstantFold = options.isSet("doConstantFold");
+        specialConstUtils = new SpecialConstantUtils(context);
     }
     // </editor-fold>
 
@@ -1255,6 +1261,9 @@
      *   (v) is native.
     */
    public boolean isSignaturePolymorphic(MethodSymbol msym) {
+       if (doConstantFold && specialConstUtils.isIntrinsicsIndy(msym)) {
+           return true;
+       }
        List<Type> argtypes = msym.type.getParameterTypes();
        return (msym.flags_field & NATIVE) != 0 &&
               (msym.owner == syms.methodHandleType.tsym || msym.owner == syms.varHandleType.tsym) &&
@@ -4273,6 +4282,22 @@
         return syms.enterClass(syms.java_base, syms.boxedName[t.getTag().ordinal()]);
     }
 
+    public ClassSymbol boxedClass(String descriptor) {
+        switch (descriptor) {
+            case "I": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.INT.ordinal()]);
+            case "J": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.LONG.ordinal()]);
+            case "S": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.SHORT.ordinal()]);
+            case "B": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.BYTE.ordinal()]);
+            case "C": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.CHAR.ordinal()]);
+            case "F": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.FLOAT.ordinal()]);
+            case "D": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.DOUBLE.ordinal()]);
+            case "Z": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.BOOLEAN.ordinal()]);
+            case "V": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.VOID.ordinal()]);
+            default:
+                throw new AssertionError("invalid primitive descriptor " + descriptor);
+        }
+    }
+
     /**
      * Return the boxed type if 't' is primitive, otherwise return 't' itself.
      */
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Sep 29 14:47:23 2017 -0700
@@ -46,9 +46,11 @@
 import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
 import com.sun.tools.javac.jvm.*;
+
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArgs;
+
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
@@ -69,6 +71,7 @@
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
+
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
 
 /** This is the main context-dependent analysis phase in GJC. It
@@ -148,7 +151,6 @@
         argumentAttr = ArgumentAttr.instance(context);
 
         Options options = Options.instance(context);
-
         Source source = Source.instance(context);
         allowStringsInSwitch = source.allowStringsInSwitch();
         allowPoly = source.allowPoly();
@@ -2021,6 +2023,7 @@
             Type capturedRes = resultInfo.checkContext.inferenceContext().cachedCapture(tree, restype, true);
             result = check(tree, capturedRes, KindSelector.VAL, resultInfo);
         }
+        tree.resolutionPhase = localEnv.info.pendingResolutionPhase;
         chk.validate(tree.typeargs, localEnv);
     }
     //where
@@ -3372,7 +3375,7 @@
 
             // If the argument is constant, fold it.
             if (argtype.constValue() != null) {
-                Type ctype = cfolder.fold1(opc, argtype);
+                Type ctype = cfolder.fold1(opc, argtype, argtype.constValue());
                 if (ctype != null) {
                     owntype = cfolder.coerce(ctype, owntype);
                 }
@@ -3395,7 +3398,7 @@
             int opc = ((OperatorSymbol)operator).opcode;
             // If both arguments are constants, fold them.
             if (left.constValue() != null && right.constValue() != null) {
-                Type ctype = cfolder.fold2(opc, left, right);
+                Type ctype = cfolder.fold2(opc, left, right, left.constValue(), right.constValue());
                 if (ctype != null) {
                     owntype = cfolder.coerce(ctype, owntype);
                 }
@@ -5065,7 +5068,7 @@
      * the compiler has encountered some errors (which might have ended up
      * terminating attribution abruptly); if the compiler is used in fail-over
      * mode (e.g. by an IDE) and the AST contains semantic errors, this routine
-     * prevents NPE to be progagated during subsequent compilation steps.
+     * prevents NPE to be propagated during subsequent compilation steps.
      */
     public void postAttr(JCTree tree) {
         new PostAttrAnalyzer().scan(tree);
@@ -5234,5 +5237,4 @@
             }
         }.scan(pid);
     }
-
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstFold.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstFold.java	Fri Sep 29 14:47:23 2017 -0700
@@ -81,9 +81,8 @@
      *  @param operand   The operation's operand type.
      *                   Argument types are assumed to have non-null constValue's.
      */
-    Type fold1(int opcode, Type operand) {
+    Type fold1(int opcode, Type operand, Object od) {
         try {
-            Object od = operand.constValue();
             switch (opcode) {
             case nop:
                 return operand;
@@ -133,17 +132,17 @@
      *  @param left      The type of the operation's left operand.
      *  @param right     The type of the operation's right operand.
      */
-    Type fold2(int opcode, Type left, Type right) {
+    Type fold2(int opcode, Type left, Type right, Object l, Object r) {
         try {
+            Assert.check(l != null);
+            Assert.check(r != null);
             if (opcode > ByteCodes.preMask) {
                 // we are seeing a composite instruction of the form xcmp; ifxx.
                 // In this case fold both instructions separately.
-                Type t1 = fold2(opcode >> ByteCodes.preShift, left, right);
+                Type t1 = fold2(opcode >> ByteCodes.preShift, left, right, l, r);
                 return (t1.constValue() == null) ? t1
-                    : fold1(opcode & ByteCodes.preMask, t1);
+                    : fold1(opcode & ByteCodes.preMask, t1, t1.constValue());
             } else {
-                Object l = left.constValue();
-                Object r = right.constValue();
                 switch (opcode) {
                 case iadd:
                     return syms.intType.constType(intValue(l) + intValue(r));
@@ -293,8 +292,7 @@
                 case if_acmpne:
                     return syms.booleanType.constType(b2i(!l.equals(r)));
                 case string_add:
-                    return syms.stringType.constType(
-                        left.stringValue() + right.stringValue());
+                    return syms.stringType.constType(left.stringValue(l) + right.stringValue(r));
                 default:
                     return null;
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstablesVisitor.java	Fri Sep 29 14:47:23 2017 -0700
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2017, 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 java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
+import com.sun.tools.javac.code.Symbol.IntrinsicsLDCMethodSymbol;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.ArrayType;
+import com.sun.tools.javac.code.Type.MethodType;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
+import com.sun.tools.javac.jvm.Pool;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCConditional;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCTypeCast;
+import com.sun.tools.javac.tree.JCTree.JCUnary;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+import com.sun.tools.javac.util.Options;
+import com.sun.tools.javac.util.SpecialConstantUtils;
+
+import static com.sun.tools.javac.code.Flags.EFFECTIVELY_FINAL;
+import static com.sun.tools.javac.code.Flags.FINAL;
+import static com.sun.tools.javac.code.Kinds.Kind.VAR;
+import static com.sun.tools.javac.code.TypeTag.ARRAY;
+import static com.sun.tools.javac.code.TypeTag.NONE;
+import static com.sun.tools.javac.tree.JCTree.Tag.SELECT;
+
+/**
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class ConstablesVisitor extends TreeScanner {
+    protected static final Context.Key<ConstablesVisitor> constablesVisitorKey = new Context.Key<>();
+
+    public static ConstablesVisitor instance(Context context) {
+        ConstablesVisitor instance = context.get(constablesVisitorKey);
+        if (instance == null)
+            instance = new ConstablesVisitor(context);
+        return instance;
+    }
+
+    private final Symtab syms;
+    private final Names names;
+    private final Types types;
+    private final Resolve rs;
+    private final Log log;
+    private final ConstFold cfolder;
+    private final SpecialConstantUtils specialConstantUtils;
+
+    protected ConstablesVisitor(Context context) {
+        context.put(constablesVisitorKey, this);
+        Options options = Options.instance(context);
+        doConstantFold = options.isSet("doConstantFold");
+        syms = Symtab.instance(context);
+        names = Names.instance(context);
+        types = Types.instance(context);
+        rs = Resolve.instance(context);
+        log = Log.instance(context);
+        cfolder = ConstFold.instance(context);
+        specialConstantUtils = new SpecialConstantUtils(context);
+        elementToConstantMap = new HashMap<>();
+        specialConstantsHelper = new SpecialConstantsHelper(types, names, syms, rs, log, specialConstantUtils, elementToConstantMap);
+    }
+
+    /**
+     * Switch: fold special constants
+     */
+    private final boolean doConstantFold;
+
+    private Env<AttrContext> attrEnv;
+
+    public void analyzeTree(JCTree tree, Env<AttrContext> attrEnv) {
+        if (!doConstantFold) {
+            return;
+        }
+        this.attrEnv = attrEnv;
+        scan(tree);
+        elementToConstantMap.clear();
+    }
+
+    Map<Object, Object> elementToConstantMap;
+
+    @Override
+    public void visitVarDef(JCVariableDecl tree) {
+        super.visitVarDef(tree);
+        if (tree.init != null) {
+            VarSymbol v = tree.sym;
+            Object val = tree.init.type.constValue();
+            Object constant = elementToConstantMap.get(tree.init);
+            if ((val != null || constant != null) &&
+                    ((v.flags_field & FINAL) != 0 ||
+                    (v.flags_field & EFFECTIVELY_FINAL) != 0)) {
+                if (val != null) {
+                    v.setData(val);
+                    tree.type = tree.type.constType(val);
+                } else {
+                    elementToConstantMap.remove(tree.init);
+                    elementToConstantMap.put(v, constant);
+                }
+            }
+        }
+    }
+
+    Object getConstant(JCTree tree) {
+        return tree.type.constValue() != null ?
+                tree.type.constValue() :
+                elementToConstantMap.get(tree);
+    }
+
+    @Override
+    public void visitBinary(JCBinary tree) {
+        super.visitBinary(tree);
+        if (tree.type.constValue() == null &&
+                getConstant(tree.lhs) != null &&
+                getConstant(tree.rhs) != null) {
+            Type ctype = cfolder.fold2(tree.operator.opcode, tree.lhs.type, tree.rhs.type, getConstant(tree.lhs), getConstant(tree.rhs));
+            if (ctype != null) {
+                tree.type = cfolder.coerce(ctype, tree.type);
+            }
+        }
+    }
+
+    @Override
+    public void visitUnary(JCUnary tree) {
+        super.visitUnary(tree);
+        Object constant;
+        if (tree.type.constValue() == null &&
+                (constant = getConstant(tree.arg)) != null &&
+                constant instanceof Number) {
+            Type ctype = cfolder.fold1(tree.operator.opcode, tree.arg.type, getConstant(tree.arg));
+            if (ctype != null) {
+                tree.type = cfolder.coerce(ctype, tree.type);
+            }
+        }
+    }
+
+    @Override
+    public void visitConditional(JCConditional tree) {
+        // missing
+        super.visitConditional(tree);
+        if (tree.type.constValue() == null &&
+            tree.cond.type.constValue() != null &&
+            tree.truepart.type.constValue() != null &&
+            tree.falsepart.type.constValue() != null &&
+            !tree.type.hasTag(NONE)) {
+            //constant folding
+            tree.type = cfolder.coerce(tree.cond.type.isTrue() ? tree.truepart.type : tree.falsepart.type, tree.type);
+        }
+    }
+
+    @Override
+    public void visitTypeCast(JCTypeCast tree) {
+        // missing
+        super.visitTypeCast(tree);
+        if (tree.type.constValue() == null &&
+                tree.expr.type.constValue() != null) {
+            tree.type = coerce(tree.expr.type, tree.type);
+        }
+    }
+
+    Type coerce(Type etype, Type ttype) {
+        Type coercedType = cfolder.coerce(etype, ttype);
+        if (coercedType.constValue() == null) {
+            // constant value lost in the intent
+            if (types.isConvertible(etype, ttype)) {
+                Type unboxedType = types.unboxedType(ttype);
+                if (unboxedType != Type.noType) {
+                    coercedType = cfolder.coerce(etype, unboxedType);
+                    return ttype.constType(coercedType.constValue());
+                }
+            }
+        }
+        return coercedType;
+    }
+
+    @Override
+    public void visitIdent(JCIdent tree) {
+        super.visitIdent(tree);
+        Symbol sym = TreeInfo.symbol(tree);
+        if (sym.kind == VAR) {
+            VarSymbol v = (VarSymbol)sym;
+            Object constant = v.getConstValue();
+            if (constant != null && tree.type.constValue() == null) {
+                // we are seeing an effectively final variable which has just being assigned a
+                // legacy constant, we should update the type of the tree if we want Gen to generate
+                // the right code for us
+                tree.type = tree.type.constType(constant);
+                return;
+            } else {
+                constant = elementToConstantMap.get(v);
+                constant = constant != null ?
+                        constant :
+                        specialConstantsHelper.foldTrackableField(tree, attrEnv);
+                if (constant != null) {
+                    elementToConstantMap.put(tree, constant);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void visitSelect(JCFieldAccess tree) {
+        super.visitSelect(tree);
+        Object constantType = specialConstantsHelper.foldTrackableField(tree, attrEnv);
+        if (constantType != null) {
+            elementToConstantMap.put(tree, constantType);
+        }
+    }
+
+    @Override
+    public void visitApply(JCMethodInvocation tree) {
+        super.visitApply(tree);
+        Name methName = TreeInfo.name(tree.meth);
+        boolean isConstructorCall = methName == names._this || methName == names._super;
+        if (!isConstructorCall) {
+            Object constant = specialConstantsHelper.foldMethodInvocation(tree, attrEnv);
+            Symbol msym = TreeInfo.symbol(tree.meth);
+            boolean isLDC = specialConstantUtils.isIntrinsicsLDCInvocation(msym);
+            if (constant == null && isLDC) {
+                log.error(tree.pos(), Errors.IntrinsicsLdcMustHaveConstantArg);
+            }
+            if (constant != null) {
+                elementToConstantMap.put(tree, constant);
+                if (isLDC) {
+                    // if condy
+                    if (tree.args.head.type.tsym == syms.dynamicConstantRefType.tsym) {
+                        Object classRef =
+                                specialConstantUtils.invokeReflectiveMethod(specialConstantUtils.dynamicConstantClass, constant, "type");
+                        String descriptor = (String)specialConstantUtils.invokeReflectiveMethod(specialConstantUtils.classRefClass, classRef, "descriptorString");
+                        Type newType = specialConstantUtils.descriptorToType(descriptor, attrEnv.enclClass.sym.packge().modle, false);
+                        constant = specialConstantUtils.convertConstant(tree, attrEnv,
+                                constant, attrEnv.enclClass.sym.packge().modle);
+                        ((Pool.ConstantDynamic)constant).updateType(newType);
+                        MethodType oldMT = tree.meth.type.asMethodType();
+                        MethodType newMT = new MethodType(oldMT.argtypes, newType, oldMT.thrown, syms.methodClass);
+                        MethodSymbol newMS = new MethodSymbol(msym.flags_field, msym.name, newMT, msym.owner);
+                        TreeInfo.updateSymbol(tree.meth, msym, newMS);
+                        tree.meth.type = newMT;
+                        tree.type = newType;
+                    } else {
+                        constant = specialConstantUtils.convertConstant(tree, attrEnv,
+                                constant, attrEnv.enclClass.sym.packge().modle);
+                    }
+                    // lets update the field as condy could have changed it
+                    msym = TreeInfo.symbol(tree.meth);
+                    IntrinsicsLDCMethodSymbol ldcSymbol = new IntrinsicsLDCMethodSymbol(
+                            msym.flags_field, msym.name, msym.type, msym.owner, constant);
+                    TreeInfo.updateSymbol(tree, msym, ldcSymbol);
+                }
+            } else if (specialConstantUtils.isIntrinsicsIndy(tree)) {
+                List<Object> constants = specialConstantsHelper.extractAllConstansOrNone(List.of(tree.args.head, tree.args.tail.head));
+                if (constants.isEmpty()) {
+                    log.error(tree.args.head.pos(), Errors.IntrinsicsIndyMustHaveConstantArg);
+                } else {
+                    Object bootstrapSpecifier = constants.head;
+                    String invocationName = (String)constants.tail.head;
+                    if (invocationName.isEmpty()) {
+                        log.error(tree.args.tail.head.pos(), Errors.InvocationNameCannotBeEmpty);
+                    }
+                    Object mh = specialConstantUtils.invokeReflectiveMethod(specialConstantUtils.bootstrapSpecifierClass,
+                            bootstrapSpecifier, "method");
+                    Pool.MethodHandle mHandle = (Pool.MethodHandle)specialConstantUtils
+                            .convertConstant(tree, attrEnv, mh, attrEnv.enclClass.sym.packge().modle);
+                    boolean correct = false;
+                    if (mHandle.refKind == 6 || mHandle.refKind == 8) {
+                        MethodSymbol ms = (MethodSymbol)mHandle.refSym;
+                        MethodType mt = (MethodType)ms.type;
+                        correct = (mt.argtypes.size() >= 3 &&
+                            mt.argtypes.head.tsym == syms.methodHandlesLookupType.tsym &&
+                            mt.argtypes.tail.head.tsym == syms.stringType.tsym &&
+                            mt.argtypes.tail.tail.head.tsym == syms.methodTypeType.tsym);
+                    }
+                    if (!correct) {
+                        log.error(tree.args.head.pos(), Errors.MethodHandleNotSuitableIndy(mHandle.refSym.type));
+                    }
+
+                    ListBuffer<Type> arguments = new ListBuffer<>();
+                    tree.args = tree.args.tail.tail;
+                    tree.args.forEach(arg -> arguments.add(arg.type));
+                    Object[] bsmArgs = (Object[])specialConstantUtils.invokeReflectiveMethod(specialConstantUtils.bootstrapSpecifierClass, bootstrapSpecifier, "arguments");
+                    Object[] convertedBsmArgs = specialConstantUtils.convertConstants(tree, attrEnv, bsmArgs, attrEnv.enclClass.sym.packge().modle, true);
+                    MethodType mType = new MethodType(arguments.toList(), tree.type, List.nil(), syms.methodClass);
+                    DynamicMethodSymbol dynSym = new DynamicMethodSymbol(
+                            names.fromString(invocationName),
+                            syms.noSymbol,
+                            mHandle.refKind,
+                            (MethodSymbol)mHandle.refSym,
+                            mType,
+                            convertedBsmArgs);
+                    TreeInfo.updateSymbol(tree, msym, dynSym);
+                    tree.meth.type = mType;
+                }
+            }
+        }
+    }
+
+    final SpecialConstantsHelper specialConstantsHelper;
+
+    public static class SpecialConstantsHelper {
+        final Types types;
+        final Names names;
+        final Symtab syms;
+        final Resolve rs;
+        final Log log;
+        final SpecialConstantUtils specialConstantUtils;
+        final Map<Object, Object> elementToConstantMap;
+
+        public SpecialConstantsHelper(
+                Types types,
+                Names names,
+                Symtab syms,
+                Resolve rs,
+                Log log,
+                SpecialConstantUtils specialConstantUtils,
+                Map<Object, Object> elementsToConstantsMap) {
+            this.syms = syms;
+            this.types = types;
+            this.names = names;
+            this.rs = rs;
+            this.log = log;
+            this.specialConstantUtils = specialConstantUtils;
+            this.elementToConstantMap = elementsToConstantsMap;
+        }
+
+        /* This method doesnt verify that the annotated field is static it is assumed that
+         * it has to be
+         */
+        Object foldTrackableField(final JCTree tree, final Env<AttrContext> env) {
+            Symbol sym = TreeInfo.symbol(tree);
+            boolean trackableConstant = sym.attribute(syms.trackableConstantType.tsym) != null &&
+                    sym.packge().modle == syms.java_base;
+            if (trackableConstant) {
+                String className = sym.owner.type.tsym.flatName().toString();
+                try {
+                    Class<?> constablesClass = Class.forName(className, false, null);
+                    MemberKind mKind = getMemberKind(constablesClass, sym.name.toString());
+                    if (mKind == MemberKind.METHOD) {
+                        // we are in the middle of a method invocation bail out
+                        return null;
+                    }
+                    Field theField = constablesClass.getField(sym.name.toString());
+                    Object value = theField.get(null);
+                    if (value != null) {
+                        return value;
+                    }
+                } catch (ClassNotFoundException |
+                        NoSuchFieldException |
+                        IllegalAccessException ex) {
+                    log.error(tree, Errors.ReflectiveError(sym.name.toString(), className));
+                }
+            }
+            return null;
+        }
+
+        enum MemberKind {
+            FIELD,
+            METHOD
+        }
+
+        MemberKind getMemberKind(Class<?> aClass, String name) {
+            try {
+                aClass.getField(name);
+                return MemberKind.FIELD;
+            } catch (NoSuchFieldException ex) {
+                return MemberKind.METHOD;
+            }
+        }
+
+        Object foldMethodInvocation(final JCMethodInvocation tree, final Env<AttrContext> env) {
+            Symbol msym = TreeInfo.symbol(tree.meth);
+            Object constant = null;
+            boolean trackableConstant = msym.attribute(syms.trackableConstantType.tsym) != null &&
+                    msym.packge().modle == syms.java_base;
+            boolean isLDC = msym.owner.type.tsym == syms.intrinsicsType.tsym && msym.name == names.ldc;
+            if (trackableConstant || isLDC) {
+                List<Object> constantArgumentValues = extractAllConstansOrNone(tree.args);
+                boolean allConstants = tree.args.isEmpty() == constantArgumentValues.isEmpty();
+                if (allConstants) {
+                    if (trackableConstant) {
+                        constant = invokeConstablesMethod(tree, env, constantArgumentValues);
+                    } else if (isLDC) {
+                        constant = constantArgumentValues.head;
+                    }
+                }
+                if (constant != null) {
+                    return constant;
+                }
+            }
+            return null;
+        }
+
+        List<Object> extractAllConstansOrNone(List<JCExpression> args) {
+            ListBuffer<Object> constantArgumentValues = new ListBuffer<>();
+            for (JCExpression arg: args) {
+                Object argConstant = arg.type.constValue();
+                if (argConstant != null) {
+                    constantArgumentValues.add(argConstant);
+                } else {
+                    argConstant = elementToConstantMap.get(arg) != null ?
+                            elementToConstantMap.get(arg) :
+                            elementToConstantMap.get(TreeInfo.symbol(arg));
+                    if (argConstant != null) {
+                        constantArgumentValues.add(argConstant);
+                    } else {
+                        return List.nil();
+                    }
+                }
+            }
+            return constantArgumentValues.toList();
+        }
+
+        // where
+            Object invokeConstablesMethod(
+                    final JCMethodInvocation tree,
+                    final Env<AttrContext> env,
+                    List<Object> constantArgumentValues) {
+                String className = "";
+                Name methodName = names.empty;
+                try {
+                    Symbol msym = TreeInfo.symbol(tree.meth);
+                    JCTree qualifierTree = (tree.meth.hasTag(SELECT))
+                        ? ((JCFieldAccess) tree.meth).selected
+                        : null;
+                    Object instance = elementToConstantMap.get(qualifierTree);
+                    className = msym.owner.type.tsym.flatName().toString();
+                    methodName = msym.name;
+                    Class<?> constablesClass = Class.forName(className, false, null);
+                    MethodType mt = msym.type.asMethodType();
+                    java.util.List<Class<?>> argumentTypes =
+                            mt.argtypes.stream().map(t -> getClassForType(t)).collect(List.collector());
+                    Method theMethod = constablesClass.getDeclaredMethod(methodName.toString(),
+                            argumentTypes.toArray(new Class<?>[argumentTypes.size()]));
+                    int modifiers = theMethod.getModifiers();
+                    Type varTypeElement = mt.getParameterTypes().last();
+                    if (varTypeElement != null) {
+                        varTypeElement = types.elemtype(varTypeElement);
+                    }
+                    Object[] args = boxArgs(
+                            mt.argtypes,
+                            constantArgumentValues,
+                            tree.resolutionPhase == MethodResolutionPhase.VARARITY ? varTypeElement : null);
+                    if ((modifiers & Modifier.STATIC) == 0) {
+                        return (instance != null) ? theMethod.invoke(instance, args) : null;
+                    }
+                    return theMethod.invoke(null, args);
+                } catch (ClassNotFoundException |
+                        SecurityException |
+                        NoSuchMethodException |
+                        IllegalAccessException |
+                        IllegalArgumentException |
+                        InvocationTargetException ex) {
+                    log.error(tree, Errors.ReflectiveError(methodName.toString(), className));
+                    return null;
+                }
+            }
+
+            Class<?> getClassForType(Type t) {
+                try {
+                    if (t.isPrimitiveOrVoid()) {
+                        return t.getTag().theClass;
+                    } else {
+                        return Class.forName(getFlatName(t), false, null);
+                    }
+                } catch (ClassNotFoundException ex) {
+                    return null;
+                }
+            }
+
+            String getFlatName(Type t) {
+                String flatName = t.tsym.flatName().toString();
+                if (t.hasTag(ARRAY)) {
+                    flatName = "";
+                    while (t.hasTag(ARRAY)) {
+                        ArrayType at = (ArrayType)t;
+                        flatName += "[";
+                        t = at.elemtype;
+                    }
+                    flatName += "L" + t.tsym.flatName().toString() + ';';
+                }
+                return flatName;
+            }
+
+            Object[] boxArgs(List<Type> parameters, List<Object> _args, Type varargsElement) {
+                java.util.List<Object> result = new java.util.ArrayList<>();
+                List<Object> args = _args;
+                if (parameters.isEmpty()) return new Object[0];
+                while (parameters.tail.nonEmpty()) {
+                    result.add(args.head);
+                    args = args.tail;
+                    parameters = parameters.tail;
+                }
+                if (varargsElement != null) {
+                    java.util.List<Object> elems = new java.util.ArrayList<>();
+                    while (args.nonEmpty()) {
+                        elems.add(args.head);
+                        args = args.tail;
+                    }
+                    Class<?> arrayClass = null;
+                    try {
+                        arrayClass = Class.forName(getFlatName(varargsElement), false, null);
+                    } catch (ClassNotFoundException ex) {}
+                    Object arr = Array.newInstance(arrayClass, elems.size());
+                    for (int i = 0; i < elems.size(); i++) {
+                        Array.set(arr, i, elems.get(i));
+                    }
+                    result.add(arr);
+                } else {
+                    if (args.length() != 1) throw new AssertionError(args);
+                    result.add(args.head);
+                }
+                return result.toArray();
+            }
+    }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Fri Sep 29 14:47:23 2017 -0700
@@ -564,32 +564,7 @@
         final Type restype;
 
         if (spMethod == null || types.isSameType(spMethod.getReturnType(), syms.objectType, true)) {
-            // The return type of the polymorphic signature is polymorphic,
-            // and is computed from the enclosing tree E, as follows:
-            // if E is a cast, then use the target type of the cast expression
-            // as a return type; if E is an expression statement, the return
-            // type is 'void'; otherwise
-            // the return type is simply 'Object'. A correctness check ensures
-            // that env.next refers to the lexically enclosing environment in
-            // which the polymorphic signature call environment is nested.
-
-            switch (env.next.tree.getTag()) {
-                case TYPECAST:
-                    JCTypeCast castTree = (JCTypeCast)env.next.tree;
-                    restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ?
-                              castTree.clazz.type :
-                              syms.objectType;
-                    break;
-                case EXEC:
-                    JCTree.JCExpressionStatement execTree =
-                            (JCTree.JCExpressionStatement)env.next.tree;
-                    restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ?
-                              syms.voidType :
-                              syms.objectType;
-                    break;
-                default:
-                    restype = syms.objectType;
-            }
+            restype = getSigPolyReturnType(env);
         } else {
             // The return type of the polymorphic signature is fixed
             // (not polymorphic)
@@ -607,6 +582,32 @@
                                           syms.methodClass);
         return mtype;
     }
+
+    public Type getSigPolyReturnType(Env<AttrContext> env) {
+        // The return type of the polymorphic signature is polymorphic,
+        // and is computed from the enclosing tree E, as follows:
+        // if E is a cast, then use the target type of the cast expression
+        // as a return type; if E is an expression statement, the return
+        // type is 'void'; otherwise
+        // the return type is simply 'Object'. A correctness check ensures
+        // that env.next refers to the lexically enclosing environment in
+        // which the polymorphic signature call environment is nested.
+        switch (env.next.tree.getTag()) {
+            case TYPECAST:
+                JCTypeCast castTree = (JCTypeCast)env.next.tree;
+                return (TreeInfo.skipParens(castTree.expr) == env.tree) ?
+                          castTree.clazz.type :
+                          syms.objectType;
+            case EXEC:
+                JCTree.JCExpressionStatement execTree =
+                        (JCTree.JCExpressionStatement)env.next.tree;
+                return (TreeInfo.skipParens(execTree.expr) == env.tree) ?
+                          syms.voidType :
+                          syms.objectType;
+            default:
+                return syms.objectType;
+        }
+    }
     //where
         class ImplicitArgType extends DeferredAttr.DeferredTypeMap {
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Sep 29 14:47:23 2017 -0700
@@ -69,7 +69,8 @@
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.type.TypeKind;
 
-import com.sun.tools.javac.main.Option;
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Symbol.DynamicFieldSymbol;
 
 /**
  * This pass desugars lambda expressions into static methods
@@ -148,6 +149,10 @@
         dumpLambdaToMethodStats = options.isSet("debug.dumpLambdaToMethodStats");
         attr = Attr.instance(context);
         forceSerializable = options.isSet("forceSerializable");
+        doConstantFold = options.isSet("doConstantFold");
+        condyForLambda = options.isSet("condyForLambda");
+        Source source = Source.instance(context);
+        allowCondyForLambda = source.allowCondyForLambda();
     }
     // </editor-fold>
 
@@ -1085,7 +1090,51 @@
             }
         }
 
-        return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
+        return doConstantFold &&
+                condyForLambda &&
+                allowCondyForLambda &&
+                !context.needsAltMetafactory() &&
+                indy_args.isEmpty() ?
+                makeCondy(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, tree.type, indy_args, samSym.name) :
+                makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
+    }
+
+    private final boolean doConstantFold;
+    /* this extra flag should be temporary and used as long as it's not possible to do the build
+     * due to the lack of support for condy in the current version of ASM present in the build
+     */
+    private final boolean condyForLambda;
+    private final boolean allowCondyForLambda;
+
+    private JCExpression makeCondy(DiagnosticPosition pos, Type site, Name bsmName,
+            List<Object> staticArgs, Type interfaceType, List<JCExpression> indyArgs,
+            Name methName) {
+        int prevPos = make.pos;
+        try {
+            make.at(pos);
+            List<Type> bsm_staticArgs = List.of(syms.methodHandlesLookupType,
+                    syms.stringType,
+                    syms.classType).appendList(bsmStaticArgToTypes(staticArgs));
+
+            Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
+                    bsmName, bsm_staticArgs, List.nil());
+
+            DynamicFieldSymbol dynSym = new DynamicFieldSymbol(methName,
+                    syms.noSymbol,
+                    bsm.isStatic() ?
+                        ClassFile.REF_invokeStatic :
+                        ClassFile.REF_invokeVirtual,
+                    (MethodSymbol)bsm,
+                    interfaceType,
+                    staticArgs.toArray());
+
+            JCIdent ident = make.Ident(dynSym);
+            ident.type = interfaceType;
+
+            return ident;
+        } finally {
+            make.at(prevPos);
+        }
     }
 
     /**
@@ -1098,7 +1147,7 @@
         int prevPos = make.pos;
         try {
             make.at(pos);
-            List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+            List<Type> bsm_staticArgs = List.of(syms.methodHandlesLookupType,
                     syms.stringType,
                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Sep 29 14:47:23 2017 -0700
@@ -3124,7 +3124,7 @@
         tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
 
         if (tree.hasTag(NOT) && tree.arg.type.constValue() != null) {
-            tree.type = cfolder.fold1(bool_not, tree.arg.type);
+            tree.type = cfolder.fold1(bool_not, tree.arg.type, tree.arg.type.constValue());
         }
 
         // If translated left hand side is an Apply, we are
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Fri Sep 29 14:47:23 2017 -0700
@@ -398,6 +398,9 @@
         public void visitIdent(JCIdent that) {}
 
         @Override
+        public void visitTypeIdent(JCPrimitiveTypeTree that) { }
+
+        @Override
         public void visitSelect(JCFieldAccess tree) {
             tree.selected.accept(this);
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Sep 29 14:47:23 2017 -0700
@@ -145,6 +145,11 @@
         inapplicableMethodException = new InapplicableMethodException(diags);
 
         allowModules = source.allowModules();
+
+        doConstantFold = options.isSet("doConstantFold");
+        if (doConstantFold) {
+            specialConstUtils = new SpecialConstantUtils(context);
+        }
     }
 
     /** error symbols, which are returned when resolution fails
@@ -2611,7 +2616,22 @@
                         return findFun(env, name, argtypes, typeargtypes,
                                 phase.isBoxingRequired(),
                                 phase.isVarargsRequired());
-                    }});
+                    }
+                    @Override
+                    Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
+                        if (sym.kind.isResolutionError()) {
+                            sym = super.access(env, pos, location, sym);
+                        } else {
+                            MethodSymbol msym = (MethodSymbol)sym;
+                            if (doConstantFold &&
+                                    (specialConstUtils.isIntrinsicsIndy(msym))) {
+                                sym.flags_field |= SIGNATURE_POLYMORPHIC;
+                                return findPolymorphicSignatureInstance(env, sym, argtypes);
+                            }
+                        }
+                        return sym;
+                    }
+                });
     }
 
     /** Resolve a qualified method identifier
@@ -2633,11 +2653,19 @@
                                   List<Type> typeargtypes) {
         return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes);
     }
-    private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext,
+    Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext,
                                   DiagnosticPosition pos, Env<AttrContext> env,
                                   Symbol location, Type site, Name name, List<Type> argtypes,
                                   List<Type> typeargtypes) {
-        return lookupMethod(env, pos, location, resolveContext, new BasicLookupHelper(name, site, argtypes, typeargtypes) {
+        return resolveQualifiedMethod(resolveContext, pos, env, location, site, name,
+                argtypes, typeargtypes, MethodResolutionPhase.VARARITY);
+    }
+    Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext,
+                                  DiagnosticPosition pos, Env<AttrContext> env,
+                                  Symbol location, Type site, Name name, List<Type> argtypes,
+                                  List<Type> typeargtypes,
+                                  MethodResolutionPhase maxPhase) {
+        return lookupMethod(env, pos, location, resolveContext, new BasicLookupHelper(name, site, argtypes, typeargtypes, maxPhase) {
             @Override
             Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
                 return findMethod(env, site, name, argtypes, typeargtypes,
@@ -2650,7 +2678,10 @@
                     sym = super.access(env, pos, location, sym);
                 } else if (allowMethodHandles) {
                     MethodSymbol msym = (MethodSymbol)sym;
-                    if ((msym.flags() & SIGNATURE_POLYMORPHIC) != 0) {
+                    if ((msym.flags() & SIGNATURE_POLYMORPHIC) != 0 ||
+                        doConstantFold &&
+                        specialConstUtils.isIntrinsicsIndy(msym)) {
+                        sym.flags_field |= SIGNATURE_POLYMORPHIC;
                         return findPolymorphicSignatureInstance(env, sym, argtypes);
                     }
                 }
@@ -2659,6 +2690,9 @@
         });
     }
 
+    private boolean doConstantFold;
+    private SpecialConstantUtils specialConstUtils;
+
     /** Find or create an implicit method of exactly the given type (after erasure).
      *  Searches in a side table, not the main scope of the site.
      *  This emulates the lookup process required by JSR 292 in JVM.
@@ -4607,7 +4641,7 @@
         }
     }
 
-    enum MethodResolutionPhase {
+    public enum MethodResolutionPhase {
         BASIC(false, false),
         BOX(true, false),
         VARARITY(true, true) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java	Fri Sep 29 14:47:23 2017 -0700
@@ -84,6 +84,7 @@
     public final static int CONSTANT_NameandType = 12;
     public final static int CONSTANT_MethodHandle = 15;
     public final static int CONSTANT_MethodType = 16;
+    public final static int CONSTANT_ConstantDynamic = 17;
     public final static int CONSTANT_InvokeDynamic = 18;
     public final static int CONSTANT_Module = 19;
     public final static int CONSTANT_Package = 20;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Sep 29 14:47:23 2017 -0700
@@ -405,6 +405,7 @@
             case CONSTANT_NameandType:
             case CONSTANT_Integer:
             case CONSTANT_Float:
+            case CONSTANT_ConstantDynamic:
             case CONSTANT_InvokeDynamic:
                 bp = bp + 4;
                 break;
@@ -480,6 +481,7 @@
         case CONSTANT_MethodType:
             skipBytes(3);
             break;
+        case CONSTANT_ConstantDynamic:
         case CONSTANT_InvokeDynamic:
             skipBytes(5);
             break;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Fri Sep 29 14:47:23 2017 -0700
@@ -48,7 +48,6 @@
 import com.sun.tools.javac.jvm.Pool.Method;
 import com.sun.tools.javac.jvm.Pool.MethodHandle;
 import com.sun.tools.javac.jvm.Pool.Variable;
-import com.sun.tools.javac.main.Option;
 import com.sun.tools.javac.util.*;
 
 import static com.sun.tools.javac.code.Flags.*;
@@ -146,6 +145,9 @@
     /** The name table. */
     private final Names names;
 
+    /** The symbol table. */
+    private final Symtab syms;
+
     /** Access to files. */
     private final JavaFileManager fileManager;
 
@@ -174,6 +176,7 @@
 
         log = Log.instance(context);
         names = Names.instance(context);
+        syms = Symtab.instance(context);
         options = Options.instance(context);
         target = Target.instance(context);
         source = Source.instance(context);
@@ -395,26 +398,26 @@
                     //invokedynamic
                     DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m;
                     MethodHandle handle = new MethodHandle(dynSym.bsmKind, dynSym.bsm, types);
-                    DynamicMethod.BootstrapMethodsKey key = new DynamicMethod.BootstrapMethodsKey(dynSym, types);
-
-                    // Figure out the index for existing BSM; create a new BSM if no key
-                    DynamicMethod.BootstrapMethodsValue val = bootstrapMethods.get(key);
-                    if (val == null) {
-                        int index = bootstrapMethods.size();
-                        val = new DynamicMethod.BootstrapMethodsValue(handle, index);
-                        bootstrapMethods.put(key, val);
-                    }
-
-                    //init cp entries
-                    pool.put(names.BootstrapMethods);
-                    pool.put(handle);
-                    for (Object staticArg : dynSym.staticArgs) {
-                        pool.put(staticArg);
-                    }
+                    DynamicMethod.BootstrapMethodsValue val = writeDynSymbol(dynSym, handle);
                     poolbuf.appendByte(CONSTANT_InvokeDynamic);
                     poolbuf.appendChar(val.index);
                     poolbuf.appendChar(pool.put(nameType(dynSym)));
                 }
+            } else if (value instanceof Pool.ConstantDynamic) {
+                Pool.ConstantDynamic cd = (Pool.ConstantDynamic)value;
+                MethodHandle handle = cd.bsm;
+                DynamicMethodSymbol dynSym = new DynamicMethodSymbol(
+                        handle.refSym.name,
+                        syms.noSymbol,
+                        handle.refKind,
+                        (MethodSymbol)handle.refSym,
+                        handle.refSym.type,
+                        cd.args);
+                DynamicMethod.BootstrapMethodsValue val = writeDynSymbol(dynSym, handle);
+                poolbuf.appendByte(CONSTANT_ConstantDynamic);
+                poolbuf.appendChar(val.index);
+                NameAndType nt = new NameAndType(cd.name, cd.type, cd.types);
+                poolbuf.appendChar(pool.put(nt));
             } else if (value instanceof VarSymbol) {
                 VarSymbol v = (VarSymbol)value;
                 poolbuf.appendByte(CONSTANT_Fieldref);
@@ -492,6 +495,26 @@
         putChar(poolbuf, poolCountIdx, pool.pp);
     }
 
+    DynamicMethod.BootstrapMethodsValue writeDynSymbol(DynamicMethodSymbol dynSym, MethodHandle handle) {
+        DynamicMethod.BootstrapMethodsKey key = new DynamicMethod.BootstrapMethodsKey(dynSym, types);
+
+        // Figure out the index for existing BSM; create a new BSM if no key
+        DynamicMethod.BootstrapMethodsValue val = bootstrapMethods.get(key);
+        if (val == null) {
+            int index = bootstrapMethods.size();
+            val = new DynamicMethod.BootstrapMethodsValue(handle, index);
+            bootstrapMethods.put(key, val);
+        }
+
+        //init cp entries
+        pool.put(names.BootstrapMethods);
+        pool.put(handle);
+        for (Object staticArg : dynSym.staticArgs) {
+            pool.put(staticArg);
+        }
+        return val;
+    }
+
     /** Given a symbol, return its name-and-type.
      */
     NameAndType nameType(Symbol sym) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Fri Sep 29 14:47:23 2017 -0700
@@ -29,6 +29,7 @@
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Types.UniqueType;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.jvm.Pool.ConstantDynamic;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -920,6 +921,7 @@
         if (o instanceof ClassSymbol) return syms.classType;
         if (o instanceof Pool.MethodHandle) return syms.methodHandleType;
         if (o instanceof UniqueType) return typeForPool(((UniqueType)o).type);
+        if (o instanceof Pool.ConstantDynamic) return ((Pool.ConstantDynamic)o).type;
         if (o instanceof Type) {
             Type ty = (Type) o;
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Sep 29 14:47:23 2017 -0700
@@ -25,6 +25,7 @@
 
 package com.sun.tools.javac.jvm;
 
+
 import com.sun.tools.javac.tree.TreeInfo.PosKind;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -33,6 +34,7 @@
 import com.sun.tools.javac.code.Attribute.TypeCompound;
 import com.sun.tools.javac.code.Symbol.VarSymbol;
 import com.sun.tools.javac.comp.*;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.tree.*;
 
 import com.sun.tools.javac.code.Symbol.*;
@@ -127,7 +129,6 @@
         debugCode = options.isSet("debug.code");
         allowBetterNullChecks = target.hasObjects();
         pool = new Pool(types);
-
         // ignore cldc because we cannot have both stackmap formats
         this.stackMap = StackMapFormat.JSR202;
         annotate = Annotate.instance(context);
@@ -1641,18 +1642,30 @@
 
     public void visitApply(JCMethodInvocation tree) {
         setTypeAnnotationPositions(tree.pos);
-        // Generate code for method.
-        Item m = genExpr(tree.meth, methodType);
-        // Generate code for all arguments, where the expected types are
-        // the parameters of the method's external type (that is, any implicit
-        // outer instance of a super(...) call appears as first parameter).
         MethodSymbol msym = (MethodSymbol)TreeInfo.symbol(tree.meth);
-        genArgs(tree.args,
-                msym.externalType(types).getParameterTypes());
-        if (!msym.isDynamic()) {
-            code.statBegin(tree.pos);
+        Item m;
+        if (msym.isIntrinsicsLDC()) {
+            Object constant = ((IntrinsicsLDCMethodSymbol)msym).getConstant();
+            // primitives special case
+            if (constant instanceof VarSymbol && ((VarSymbol)constant).name == names.TYPE) {
+                m = items.makeStaticItem((Symbol)constant);
+            } else {
+                m = items.makeImmediateItem(pt, constant);
+            }
+            result = m.coerce(pt).load();
+        } else {
+            // Generate code for method.
+            m = genExpr(tree.meth, methodType);
+            // Generate code for all arguments, where the expected types are
+            // the parameters of the method's external type (that is, any implicit
+            // outer instance of a super(...) call appears as first parameter).
+            genArgs(tree.args,
+                    msym.externalType(types).getParameterTypes());
+            if (!msym.isDynamic()) {
+                code.statBegin(tree.pos);
+            }
+            result = m.invoke();
         }
-        result = m.invoke();
     }
 
     public void visitConditional(JCConditional tree) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Fri Sep 29 14:47:23 2017 -0700
@@ -26,6 +26,7 @@
 package com.sun.tools.javac.jvm;
 
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Kinds.Kind;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.jvm.Code.*;
@@ -472,8 +473,11 @@
         }
 
         Item load() {
-            assert false;
-            return null;
+            Assert.check(member.kind == Kind.VAR);
+            Type type = member.erasure(types);
+            int rescode = Code.typecode(type);
+            code.emitLdc(pool.put(member));
+            return stackItem[rescode];
         }
 
         void store() {
@@ -481,7 +485,7 @@
         }
 
         Item invoke() {
-            // assert target.hasNativeInvokeDynamic();
+            Assert.check(member.kind == Kind.MTH);
             MethodType mtype = (MethodType)member.erasure(types);
             int rescode = Code.typecode(mtype.restype);
             code.emitInvokedynamic(pool.put(member), mtype);
@@ -577,45 +581,49 @@
         }
 
         Item load() {
-            switch (typecode) {
-            case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
-                int ival = ((Number)value).intValue();
-                if (-1 <= ival && ival <= 5)
-                    code.emitop0(iconst_0 + ival);
-                else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
-                    code.emitop1(bipush, ival);
-                else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
-                    code.emitop2(sipush, ival);
-                else
+            if (value instanceof Pool.ConstantDynamic) {
+                ldc();
+            } else {
+                switch (typecode) {
+                case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
+                    int ival = ((Number)value).intValue();
+                    if (-1 <= ival && ival <= 5)
+                        code.emitop0(iconst_0 + ival);
+                    else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
+                        code.emitop1(bipush, ival);
+                    else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
+                        code.emitop2(sipush, ival);
+                    else
+                        ldc();
+                    break;
+                case LONGcode:
+                    long lval = ((Number)value).longValue();
+                    if (lval == 0 || lval == 1)
+                        code.emitop0(lconst_0 + (int)lval);
+                    else
+                        ldc();
+                    break;
+                case FLOATcode:
+                    float fval = ((Number)value).floatValue();
+                    if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
+                        code.emitop0(fconst_0 + (int)fval);
+                    else {
+                        ldc();
+                    }
+                    break;
+                case DOUBLEcode:
+                    double dval = ((Number)value).doubleValue();
+                    if (isPosZero(dval) || dval == 1.0)
+                        code.emitop0(dconst_0 + (int)dval);
+                    else
+                        ldc();
+                    break;
+                case OBJECTcode:
                     ldc();
-                break;
-            case LONGcode:
-                long lval = ((Number)value).longValue();
-                if (lval == 0 || lval == 1)
-                    code.emitop0(lconst_0 + (int)lval);
-                else
-                    ldc();
-                break;
-            case FLOATcode:
-                float fval = ((Number)value).floatValue();
-                if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
-                    code.emitop0(fconst_0 + (int)fval);
-                else {
-                    ldc();
+                    break;
+                default:
+                    Assert.error();
                 }
-                break;
-            case DOUBLEcode:
-                double dval = ((Number)value).doubleValue();
-                if (isPosZero(dval) || dval == 1.0)
-                    code.emitop0(dconst_0 + (int)dval);
-                else
-                    ldc();
-                break;
-            case OBJECTcode:
-                ldc();
-                break;
-            default:
-                Assert.error();
             }
             return stackItem[typecode];
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java	Fri Sep 29 14:47:23 2017 -0700
@@ -39,6 +39,7 @@
 
 import java.util.*;
 
+import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
 
@@ -128,6 +129,8 @@
     Object makePoolValue(Object o) {
         if (o instanceof DynamicMethodSymbol) {
             return new DynamicMethod((DynamicMethodSymbol)o, types);
+        } else if (o instanceof DynamicFieldSymbol) {
+            return new Pool.ConstantDynamic((DynamicFieldSymbol)o, types);
         } else if (o instanceof MethodSymbol) {
             return new Method((MethodSymbol)o, types);
         } else if (o instanceof VarSymbol) {
@@ -182,10 +185,12 @@
 
     static class DynamicMethod extends Method {
         public Object[] uniqueStaticArgs;
+        Method internalBSM;
 
         DynamicMethod(DynamicMethodSymbol m, Types types) {
             super(m, types);
             uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types);
+            internalBSM = new Method(m.bsm, types);
         }
 
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
@@ -198,7 +203,7 @@
             if (!(any instanceof DynamicMethod)) return false;
             DynamicMethodSymbol dm1 = (DynamicMethodSymbol)other;
             DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)any).other;
-            return dm1.bsm == dm2.bsm &&
+            return internalBSM.equals(((DynamicMethod)any).internalBSM) &&
                         dm1.bsmKind == dm2.bsmKind &&
                         Arrays.equals(uniqueStaticArgs,
                             ((DynamicMethod)any).uniqueStaticArgs);
@@ -213,7 +218,7 @@
             int hash = includeDynamicArgs ? super.hashCode() : 0;
             DynamicMethodSymbol dm = (DynamicMethodSymbol)other;
             hash += dm.bsmKind * 7 +
-                    dm.bsm.hashCode() * 11;
+                    internalBSM.hashCode() * 11;
             for (int i = 0; i < dm.staticArgs.length; i++) {
                 hash += (uniqueStaticArgs[i].hashCode() * 23);
             }
@@ -289,13 +294,66 @@
         }
     }
 
+    /**
+     * Pool entry associated with dynamic constants.
+     */
+    public static class ConstantDynamic {
+        MethodHandle bsm;
+        Name name;
+        Type type;
+
+        Object[] args;
+        Types types;
+
+        public ConstantDynamic(Name name, MethodHandle bsm, Object[] args, Types types) {
+            Assert.checkNonNull(args);
+            this.bsm = bsm;
+            MethodSymbol ms = (MethodSymbol)bsm.refSym;
+            MethodType mt = (MethodType)ms.type;
+            this.name = name;
+            this.type = mt.restype;
+            this.args = args;
+            this.types = types;
+        }
+
+        public ConstantDynamic(DynamicFieldSymbol dynField, Types types) {
+            this.bsm = new MethodHandle(dynField.bsmKind, dynField.bsm, types);
+            this.name = dynField.name;
+            this.type = dynField.type;
+            this.args = dynField.staticArgs;
+            this.types = types;
+        }
+
+        @Override
+        public int hashCode() {
+            return bsm.hashCode() * 67 + name.hashCode() + type.hashCode() * 13;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ConstantDynamic) {
+                ConstantDynamic that = (ConstantDynamic)obj;
+                return that.bsm.equals(bsm) &&
+                        types.isSameType(that.type, type) &&
+                        that.name.equals(name) &&
+                        that.args.equals(args);
+            } else {
+                return false;
+            }
+        }
+
+        public void updateType(Type type) {
+            this.type = type;
+        }
+    }
+
     public static class MethodHandle {
 
         /** Reference kind - see ClassFile */
-        int refKind;
+        public int refKind;
 
         /** Reference symbol */
-        Symbol refSym;
+        public Symbol refSym;
 
         UniqueType uniqueType;
 
@@ -359,10 +417,15 @@
                     expectedKind = MTH;
                     break;
             }
-            Assert.check(!refSym.isStatic() || staticOk);
-            Assert.check(refSym.kind == expectedKind);
-            Assert.check(nameFilter.accepts(refSym.name));
-            Assert.check(!refSym.owner.isInterface() || interfaceOwner);
+            Assert.check(!refSym.isStatic() || staticOk, "incorrect static-ness for symbol " + refSym);
+            Assert.check(refSym.kind == expectedKind, "unexpected kind for symbol " + refSym +". \n"
+                    + "Expected = " + expectedKind + "\n"
+                    + "Found = " + refSym.kind);
+            Assert.check(nameFilter.accepts(refSym.name), "incorrect name for symbol " + refSym);
+            Assert.check(!refSym.owner.isInterface() || interfaceOwner,
+                    interfaceOwner ?
+                            "interface owner expected for symbol ":
+                            "non interface owner expected for symbol " + refSym);
         }
         //where
                 Filter<Name> nonInitFilter = n -> (n != n.table.names.init && n != n.table.names.clinit);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java	Fri Sep 29 14:47:23 2017 -0700
@@ -360,7 +360,7 @@
             try {
                 make.at(pos);
 
-                List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                List<Type> bsm_staticArgs = List.of(syms.methodHandlesLookupType,
                         syms.stringType,
                         syms.methodTypeType);
 
@@ -422,7 +422,7 @@
                         // Concat the String representation of the constant, except
                         // for the case it contains special tags, which requires us
                         // to expose it as detached constant.
-                        String a = arg.type.stringValue();
+                        String a = arg.type.stringValue(constVal);
                         if (a.indexOf(TAG_CONST) != -1 || a.indexOf(TAG_ARG) != -1) {
                             recipe.append(TAG_CONST);
                             staticArgs.add(a);
@@ -471,7 +471,7 @@
                     constTypes.add(syms.stringType);
                 }
 
-                List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                List<Type> bsm_staticArgs = List.of(syms.methodHandlesLookupType,
                         syms.stringType,
                         syms.methodTypeType)
                         .append(syms.stringType)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Sep 29 14:47:23 2017 -0700
@@ -298,6 +298,10 @@
      */
     protected Flow flow;
 
+    /** The constables analyzer.
+     */
+    protected ConstablesVisitor constablesVisitor;
+
     /** The modules visitor
      */
     protected Modules modules;
@@ -407,6 +411,7 @@
         chk = Check.instance(context);
         gen = Gen.instance(context);
         flow = Flow.instance(context);
+        constablesVisitor = ConstablesVisitor.instance(context);
         transTypes = TransTypes.instance(context);
         lower = Lower.instance(context);
         annotate = Annotate.instance(context);
@@ -1397,6 +1402,8 @@
 
                 analyzer.flush(env);
 
+                constablesVisitor.analyzeTree(env.tree, env);
+
                 results.add(env);
             }
             finally {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Sep 29 14:47:23 2017 -0700
@@ -3175,3 +3175,34 @@
 # 0: string, 1: string
 compiler.err.illegal.argument.for.option=\
     illegal argument for {0}: {1}
+
+###
+# constant folding errors
+
+# 0: type
+compiler.err.method.handle.not.suitable.indy=\
+    the method handle provided, with type: {0}\n\
+    cannot specify a bootstrap method
+
+compiler.err.initializer.must.be.constant=\
+    initializer must be constant
+
+compiler.err.intrinsics.ldc.must.have.constant.arg=\
+    argument to ldc() must be a constant
+
+compiler.err.intrinsics.indy.must.have.constant.arg=\
+    argument to invokedynamic() must be a constant
+
+compiler.err.invocation.name.cannot.be.empty=\
+    invocation name cannot be an empty string
+
+compiler.err.wrong.number.of.dynamic.args.indy=\
+    wrong number of dynamic arguments for invokedynamic()
+
+compiler.err.type.mismatch.dynamic.arg=\
+    type mismatch between dynamic argument and provided method type at invokedynamic()
+
+# 0: string, 1: string
+compiler.err.reflective.error=\
+    error in reflective call\n\
+    while trying to invoke method \"{0}\" of class \"{1}\"
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Sep 29 14:47:23 2017 -0700
@@ -38,6 +38,7 @@
 import com.sun.tools.javac.code.Directive.RequiresDirective;
 import com.sun.tools.javac.code.Scope.*;
 import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.Resolve;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -1619,6 +1620,7 @@
         public JCExpression meth;
         public List<JCExpression> args;
         public Type varargsElement;
+        public Resolve.MethodResolutionPhase resolutionPhase;
         protected JCMethodInvocation(List<JCExpression> typeargs,
                         JCExpression meth,
                         List<JCExpression> args)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Fri Sep 29 14:47:23 2017 -0700
@@ -858,11 +858,66 @@
             return symbol(((JCAnnotatedType) tree).underlyingType);
         case REFERENCE:
             return ((JCMemberReference) tree).sym;
+        case VARDEF :
+            return ((JCVariableDecl)tree).sym;
+        case TYPEIDENT:
+            return ((JCPrimitiveTypeTree)tree).type.tsym;
+        case TYPEARRAY:
+            return ((JCArrayTypeTree)tree).type.tsym;
+        case APPLY:
+            return symbol(((JCMethodInvocation)tree).meth);
         default:
             return null;
         }
     }
 
+    public static void updateSymbol(JCTree tree, Symbol oldSymbol, Symbol newSymbol) {
+        tree = skipParens(tree);
+        switch (tree.getTag()) {
+        case IDENT:
+            if (((JCIdent) tree).sym == oldSymbol) {
+                ((JCIdent) tree).sym = newSymbol;
+            }
+            return;
+        case SELECT:
+            if (((JCFieldAccess) tree).sym == oldSymbol) {
+                ((JCFieldAccess) tree).sym = newSymbol;
+            }
+            return;
+        case TYPEAPPLY:
+            updateSymbol(((JCTypeApply) tree).clazz, oldSymbol, newSymbol);
+            return;
+        case ANNOTATED_TYPE:
+            updateSymbol(((JCAnnotatedType) tree).underlyingType, oldSymbol, newSymbol);
+            return;
+        case REFERENCE:
+            if (((JCMemberReference) tree).sym == oldSymbol) {
+                ((JCMemberReference) tree).sym = newSymbol;
+            }
+            return;
+        case VARDEF :
+            if (((JCVariableDecl)tree).sym == oldSymbol) {
+                ((JCVariableDecl)tree).sym = (Symbol.VarSymbol)newSymbol;
+            }
+            return;
+        case TYPEIDENT:
+            if (((JCPrimitiveTypeTree)tree).type.tsym == oldSymbol) {
+                ((JCPrimitiveTypeTree)tree).type.tsym = (Symbol.TypeSymbol)newSymbol;
+            }
+            return;
+        case TYPEARRAY:
+            if (((JCArrayTypeTree)tree).type.tsym == oldSymbol) {
+                ((JCArrayTypeTree)tree).type.tsym = (Symbol.TypeSymbol)newSymbol;
+            }
+            return;
+        case APPLY:
+            updateSymbol(((JCMethodInvocation)tree).meth, oldSymbol, newSymbol);
+            return;
+        default:
+            return;
+        }
+    }
+
     /** Return true if this is a nonstatic selection. */
     public static boolean nonstaticSelect(JCTree tree) {
         tree = skipParens(tree);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Fri Sep 29 14:38:51 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Fri Sep 29 14:47:23 2017 -0700
@@ -185,6 +185,21 @@
     public final Name RUNTIME;
     public final Name SOURCE;
 
+    // members of java.lang.invoke.Constables
+    public final Name methodType;
+    public final Name virtualMethodHandle;
+    public final Name staticMethodHandle;
+    public final Name getterMethodHandle;
+    public final Name staticGetterMethodHandle;
+    public final Name setterMethodHandle;
+    public final Name staticSetterMethodHandle;
+    public final Name constructorMethodHandle;
+    public final Name specialMethodHandle;
+    public final Name indyDescriptor;
+    public final Name invokedynamic;
+    public final Name of;
+    public final Name ldc;
+
     // other identifiers
     public final Name T;
     public final Name deprecated;
@@ -348,6 +363,21 @@
         RUNTIME = fromString("RUNTIME");
         SOURCE = fromString("SOURCE");
 
+        // members of java.lang.invoke.Constables
+        methodType = fromString("methodType");
+        virtualMethodHandle = fromString("virtualMethodHandle");
+        staticMethodHandle = fromString("staticMethodHandle");
+        getterMethodHandle = fromString("getterMethodHandle");
+        staticGetterMethodHandle = fromString("staticGetterMethodHandle");
+        setterMethodHandle = fromString("setterMethodHandle");
+        staticSetterMethodHandle = fromString("staticSetterMethodHandle");
+        constructorMethodHandle = fromString("constructorMethodHandle");
+        specialMethodHandle = fromString("specialMethodHandle");
+        indyDescriptor = fromString("indyDescriptor");
+        invokedynamic = fromString("invokedynamic");
+        of = fromString("of");
+        ldc = fromString("ldc");
+
         // other identifiers
         T = fromString("T");
         deprecated = fromString("deprecated");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/SpecialConstantUtils.java	Fri Sep 29 14:47:23 2017 -0700
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2016, 2017, 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.util;
+
+import java.lang.reflect.Field;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.charset.Charset;
+
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symbol.ModuleSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.ArrayType;
+import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.Type.MethodType;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.AttrContext;
+import com.sun.tools.javac.comp.Env;
+import com.sun.tools.javac.comp.Resolve;
+import com.sun.tools.javac.jvm.ClassFile;
+import com.sun.tools.javac.jvm.Pool;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.TreeInfo;
+
+import static com.sun.tools.javac.code.Flags.STATIC;
+import static com.sun.tools.javac.code.TypeTag.ARRAY;
+import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
+
+/** This class is a support tool to parse a method descriptor and obtain a list of the types
+ *  represented in it.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class SpecialConstantUtils {
+
+    public SpecialConstantUtils(Context context) {
+        types = Types.instance(context);
+        names = Names.instance(context);
+        syms = Symtab.instance(context);
+        rs = Resolve.instance(context);
+        log = Log.instance(context);
+        try {
+            methodHandleRefClass = Class.forName("java.lang.invoke.MethodHandleRef", false, null);
+            methodTypeRefClass = Class.forName("java.lang.invoke.MethodTypeRef", false, null);
+            classRefClass = Class.forName("java.lang.invoke.ClassRef", false, null);
+            constantRefClass = Class.forName("java.lang.invoke.ConstantRef", false, null);
+            constablesClass = Class.forName("java.lang.invoke.Constables", false, null);
+            bootstrapSpecifierClass = Class.forName("java.lang.invoke.BootstrapSpecifier", false, null);
+            dynamicConstantClass = Class.forName("java.lang.invoke.DynamicConstantRef", false, null);
+        } catch (ClassNotFoundException ex) {
+            methodHandleRefClass = null;
+            methodTypeRefClass = null;
+            constantRefClass = null;
+            classRefClass = null;
+            bootstrapSpecifierClass = null;
+            dynamicConstantClass = null;
+            constablesClass = null;
+        }
+    }
+
+    final Types types;
+    final Names names;
+    final Symtab syms;
+    final Resolve rs;
+    final Log log;
+    ModuleSymbol currentModule;
+
+    /** The unread portion of the currently read type is
+     *  signature[sigp..siglimit-1].
+     */
+    byte[] signature;
+    int sigp;
+    int siglimit;
+    boolean sigEnterPhase = false;
+    byte[] signatureBuffer;
+    int sbp;
+
+    /** Convert signature to type, where signature is a byte array segment.
+     */
+    public Type descriptorToType(String descriptor, ModuleSymbol currentModule, boolean methodDescriptor) {
+        byte[] sig = descriptor.getBytes(Charset.forName("UTF-8"));
+        signature = sig;
+        sigp = 0;
+        siglimit = sig.length - 1;
+        sbp = 0;
+        signatureBuffer = new byte[sig.length];
+        this.currentModule = currentModule;
+        try {
+            if (methodDescriptor) {
+                return internalMethodDescriptorToType();
+            } else { // type descriptor
+                return sigToType();
+            }
+        } catch (AssertionError ae) {
+            return Type.noType;
+        }
+    }
+
+    private Type internalMethodDescriptorToType() {
+        if (signature[sigp] != '(') {
+            throw new AssertionError("bad descriptor");
+        }
+        sigp++;
+        List<Type> argtypes = sigToTypes(')');
+        Type restype = sigToType();
+        return new MethodType(argtypes,
+                              restype,
+                              List.nil(),
+                              syms.methodClass);
+    }
+
+    /** Convert signature to type, where signature is implicit.
+     */
+    Type sigToType() {
+        switch ((char) signature[sigp]) {
+        case 'B':
+            sigp++;
+            return syms.byteType;
+        case 'C':
+            sigp++;
+            return syms.charType;
+        case 'D':
+            sigp++;
+            return syms.doubleType;
+        case 'F':
+            sigp++;
+            return syms.floatType;
+        case 'I':
+            sigp++;
+            return syms.intType;
+        case 'J':
+            sigp++;
+            return syms.longType;
+        case 'L':
+            {
+                Type t = classSigToType();
+                if (sigp < siglimit && signature[sigp] == '.') {
+                    throw new AssertionError("deprecated inner class signature syntax");
+                }
+                return t;
+            }
+        case 'S':
+            sigp++;
+            return syms.shortType;
+        case 'V':
+            sigp++;
+            return syms.voidType;
+        case 'Z':
+            sigp++;
+            return syms.booleanType;
+        case '[':
+            sigp++;
+            return new ArrayType(sigToType(), syms.arrayClass);
+        default:
+            throw new AssertionError("bad descriptor");
+        }
+    }
+
+    /** Convert class signature to type, where signature is implicit.
+     */
+    Type classSigToType() {
+        if (signature[sigp] != 'L') {
+            throw new AssertionError("bad descriptor");
+        }
+        sigp++;
+        Type outer = Type.noType;
+        int startSbp = sbp;
+
+        while (true) {
+            final byte c = signature[sigp++];
+            switch (c) {
+
+            case ';': {         // end
+                ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
+                                                         startSbp,
+                                                         sbp - startSbp));
+
+                try {
+                    return (outer == Type.noType) ?
+                            t.erasure(types) :
+                        new ClassType(outer, List.<Type>nil(), t);
+                } finally {
+                    sbp = startSbp;
+                }
+            }
+            case '.':
+                //we have seen an enclosing non-generic class
+                if (outer != Type.noType) {
+                    ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
+                                                 startSbp,
+                                                 sbp - startSbp));
+                    outer = new ClassType(outer, List.<Type>nil(), t);
+                }
+                signatureBuffer[sbp++] = (byte)'$';
+                continue;
+            case '/':
+                signatureBuffer[sbp++] = (byte)'.';
+                continue;
+            default:
+                signatureBuffer[sbp++] = c;
+                continue;
+            }
+        }
+    }
+
+    ClassSymbol enterClass(Name name) {
+        return syms.enterClass(currentModule, name);
+    }
+
+    /** Convert (implicit) signature to list of types
+     *  until `terminator' is encountered.
+     */
+    List<Type> sigToTypes(char terminator) {
+        List<Type> head = List.of(null);
+        List<Type> tail = head;
+        while (signature[sigp] != terminator)
+            tail = tail.setTail(List.of(sigToType()));
+        sigp++;
+        return head.tail;
+    }
+
+    public Object convertConstant(JCTree tree, Env<AttrContext> attrEnv, Object constant, ModuleSymbol currentModule) {
+        return convertConstant(tree, attrEnv, constant, currentModule, false);
+    }
+
+    public Object convertConstant(JCTree tree, Env<AttrContext> attrEnv, Object constant, ModuleSymbol currentModule, boolean bsmArg) {
+        if (methodHandleRefClass.isInstance(constant)) {
+            String name = (String)invokeReflectiveMethod(methodHandleRefClass, constant, "name");
+            int refKind = (int)invokeReflectiveMethod(methodHandleRefClass, constant, "refKind");
+            Object owner = invokeReflectiveMethod(methodHandleRefClass, constant, "owner");
+            String ownerDescriptor = (String)invokeReflectiveMethod(classRefClass, owner, "descriptorString");
+            Type ownerType = descriptorToType(ownerDescriptor, currentModule, false);
+            Object mtConstant = invokeReflectiveMethod(methodHandleRefClass, constant, "type");
+            String methodTypeDesc = (String)invokeReflectiveMethod(methodTypeRefClass, mtConstant, "descriptorString");
+            MethodType mType = (MethodType)descriptorToType(
+                    methodTypeDesc, currentModule, true);
+            Symbol refSymbol = getReferenceSymbol(refKind, ownerType.tsym, name, mType);
+            return new Pool.MethodHandle(refKind, refSymbol, types);
+        } else if (methodTypeRefClass.isInstance(constant)) {
+            String descriptor = (String)invokeReflectiveMethod(methodTypeRefClass, constant, "descriptorString");
+            return types.erasure(descriptorToType(descriptor, currentModule, true));
+        } else if (classRefClass.isInstance(constant)) {
+            String descriptor = (String)invokeReflectiveMethod(classRefClass, constant, "descriptorString");
+            if ((boolean)invokeReflectiveMethod(classRefClass, constant, "isPrimitive")) {
+                if (bsmArg) {
+                    Object condy = invokeReflectiveMethod(constablesClass, null, "reduce", new Class<?>[]{constantRefClass}, new Object[]{constant});
+                    return convertConstant(tree, attrEnv, condy, currentModule);
+                } else {
+                    return rs.resolveInternalField(tree, attrEnv, types.boxedClass(descriptor).type, names.TYPE);
+                }
+            }
+            Type type = descriptorToType(descriptor, currentModule, false);
+            return type.hasTag(ARRAY) ? type : type.tsym;
+        } else if (dynamicConstantClass.isInstance(constant)) {
+            String name = (String)invokeReflectiveMethod(dynamicConstantClass, constant, "name");
+            Object mh = invokeReflectiveMethod(dynamicConstantClass, constant, "bootstrapMethod");
+            Pool.MethodHandle methodHandle = (Pool.MethodHandle)convertConstant(tree, attrEnv, mh, currentModule);
+            Object[] args = (Object[])invokeReflectiveMethod(dynamicConstantClass, constant, "bootstrapArgs");
+            Object[] convertedArgs = convertConstants(tree, attrEnv, args, currentModule, true);
+            return new Pool.ConstantDynamic(names.fromString(name), methodHandle, convertedArgs, types);
+        }
+        return constant;
+    }
+
+    public Object[] convertConstants(JCTree tree, Env<AttrContext> attrEnv, Object[] constants, ModuleSymbol currentModule, boolean bsmArgs) {
+        if (constants == null || constants.length == 0) {
+            return constants;
+        }
+        Object[] result = new Object[constants.length];
+        int i = 0;
+        for (Object constant : constants) {
+            result[i] = convertConstant(tree, attrEnv, constant, currentModule, bsmArgs);
+            i++;
+        }
+        return result;
+    }
+
+    public boolean isPrimitiveClassRef(Object constant) {
+        return classRefClass.isInstance(constant) &&
+                (boolean)invokeReflectiveMethod(classRefClass, constant, "isPrimitive");
+    }
+
+    public Class<?> methodHandleRefClass;
+    public Class<?> methodTypeRefClass;
+    public Class<?> classRefClass;
+    public Class<?> constantRefClass;
+    public Class<?> constablesClass;
+    public Class<?> bootstrapSpecifierClass;
+    public Class<?> dynamicConstantClass;
+
+    private Symbol getReferenceSymbol(int refKind, Symbol owner, String name, MethodType methodType) {
+        long flags = refKind == ClassFile.REF_getStatic ||
+                refKind == ClassFile.REF_putStatic ||
+                refKind == ClassFile.REF_invokeStatic ? STATIC : 0;
+        Name symbolName = refKind == ClassFile.REF_newInvokeSpecial ? names.init : names.fromString(name);
+        switch (refKind) {
+            case ClassFile.REF_newInvokeSpecial :
+            case ClassFile.REF_invokeVirtual:
+            case ClassFile.REF_invokeStatic:
+            case ClassFile.REF_invokeSpecial:
+            case ClassFile.REF_invokeInterface:
+                return new MethodSymbol(flags, symbolName, methodType, owner);
+            case ClassFile.REF_putField:
+                return new VarSymbol(flags, symbolName, methodType.argtypes.tail.head, owner);
+            case ClassFile.REF_putStatic:
+                return new VarSymbol(flags, symbolName, methodType.argtypes.head, owner);
+            case ClassFile.REF_getField:
+            case ClassFile.REF_getStatic:
+                return new VarSymbol(flags, symbolName, methodType.restype, owner);
+            default:
+                throw new AssertionError("invalid refKind value " + refKind);
+        }
+    }
+
+    public Object invokeReflectiveMethod(
+            Class<?> hostClass,
+            Object instance,
+            String methodName) {
+        return invokeReflectiveMethod(hostClass, instance, methodName, new Class<?>[0], new Object[0]);
+    }
+
+    public Object invokeReflectiveMethod(
+            Class<?> hostClass,
+            Object instance,
+            String methodName,
+            Class<?>[] argumentTypes,
+            Object[] arguments) {
+        Method theMethod;
+        try {
+            theMethod = hostClass.getDeclaredMethod(methodName, argumentTypes);
+            return theMethod.invoke(instance, arguments);
+        } catch (NoSuchMethodException |
+                SecurityException |
+                IllegalAccessException |
+                IllegalArgumentException |
+                InvocationTargetException ex) {
+            log.error(Errors.ReflectiveError(methodName, hostClass.getCanonicalName()));
+        }
+        return null;
+    }
+
+    public boolean isIntrinsicsIndy(JCTree tree) {
+        return isIntrinsicsIndy(TreeInfo.symbol(tree));
+    }
+
+    public boolean isIntrinsicsIndy(Symbol msym) {
+        return (msym != null &&
+                msym.owner != null &&
+                msym.owner.type != null &&
+                msym.owner.type.tsym == syms.intrinsicsType.tsym &&
+                msym.name == names.invokedynamic);
+    }
+
+    public boolean isIntrinsicsLDCInvocation(Symbol msym) {
+        return (msym != null &&
+                msym.owner != null &&
+                msym.owner.type != null &&
+                msym.owner.type.tsym == syms.intrinsicsType.tsym &&
+                msym.name == names.ldc);
+    }
+
+    public boolean isIntrinsicsLDCInvocation(JCTree tree) {
+        Symbol msym = TreeInfo.symbol(tree);
+        return (tree.hasTag(APPLY) &&
+                msym != null &&
+                msym.owner != null &&
+                msym.owner.type != null &&
+                msym.owner.type.tsym == syms.intrinsicsType.tsym &&
+                msym.name == names.ldc);
+    }
+}
--- a/test/langtools/tools/javac/specialConstantFolding/IndyNegativeTest01.out	Fri Sep 29 14:38:51 2017 -0700
+++ b/test/langtools/tools/javac/specialConstantFolding/IndyNegativeTest01.out	Fri Sep 29 14:47:23 2017 -0700
@@ -1,3 +1,2 @@
 IndyNegativeTest01.java:26:48: compiler.err.intrinsics.indy.must.have.constant.arg
-IndyNegativeTest01.java:26:59: compiler.err.intrinsics.indy.must.have.constant.arg
-2 errors
+1 error