changeset 1138:95ae37c3d0cf

Add support for creating lambda/method references through indy calls *) Added code-generation support for BootstrapMethods attribute *) Added code-generation support for CONSTANT_InvokeDynamic CP entry *) Added simple bootstrap method used to create SAM instances (simply links to the old method using dynamic proxies) *) Added desugaring support for generating invokedynamic calls
author mcimadamore
date Mon, 08 Aug 2011 13:42:09 +0100
parents b81b670567c4
children b9e08af836ed
files src/share/classes/com/sun/runtime/ProxyHelper.java src/share/classes/com/sun/tools/javac/code/Symbol.java src/share/classes/com/sun/tools/javac/code/Symtab.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java src/share/classes/com/sun/tools/javac/jvm/Gen.java src/share/classes/com/sun/tools/javac/jvm/Items.java src/share/classes/com/sun/tools/javac/jvm/Pool.java src/share/classes/com/sun/tools/javac/tree/JCTree.java src/share/classes/com/sun/tools/javac/tree/Pretty.java src/share/classes/com/sun/tools/javac/util/Names.java
diffstat 13 files changed, 585 insertions(+), 96 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/runtime/ProxyHelper.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/runtime/ProxyHelper.java	Mon Aug 08 13:42:09 2011 +0100
@@ -30,8 +30,11 @@
 import java.lang.reflect.Proxy;
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationHandler;
+import java.lang.invoke.ConstantCallSite;
+import java.lang.invoke.CallSite;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 
 /**
  * Utility class to turn a method handle into a SAM instance
@@ -109,4 +112,21 @@
             complete = true;
         }
     }
+
+    public static CallSite metaFactory(MethodHandles.Lookup caller,
+                                       String invokedName,
+                                       MethodType invokedType,
+                                       Class<?> samClass,
+                                       MethodHandle handle) throws Throwable {
+        MethodHandle mh = caller.findStatic(ProxyHelper.class,
+                                            "makeProxy",
+                                            MethodType.methodType(Object.class, Class.class, MethodHandle.class, boolean.class, Object[].class));
+
+        mh = MethodHandles.insertArguments(mh, 0, samClass);
+        mh = MethodHandles.insertArguments(mh, 0, handle);
+        
+        mh = mh.asType(invokedType);
+
+        return new ConstantCallSite(mh);
+    }
 }
--- a/src/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java	Mon Aug 08 13:42:09 2011 +0100
@@ -1079,6 +1079,10 @@
             return null;
         }
 
+        public boolean isDynamic() {
+            return false;
+        }
+
         /** find a symbol that this (proxy method) symbol implements.
          *  @param    c       The class whose members are searched for
          *                    implementations
@@ -1342,6 +1346,27 @@
         }
     }
 
+    /** A class for invokedynamic method calls.
+     */
+    public static class DynamicMethodSymbol extends MethodSymbol {
+
+        public Object[] staticArgs;
+        public Symbol bsm;
+        public int bsmKind;
+
+        public DynamicMethodSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) {
+            super(0, name, type, owner);
+            this.bsm = bsm;
+            this.bsmKind = bsmKind;
+            this.staticArgs = staticArgs;
+        }
+
+        @Override
+        public boolean isDynamic() {
+            return true;
+        }
+    }
+
     /** A class for predefined operators.
      */
     public static class OperatorSymbol extends MethodSymbol {
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java	Mon Aug 08 13:42:09 2011 +0100
@@ -459,7 +459,7 @@
         methodHandleType = enterClass("java.lang.invoke.MethodHandle");
         methodTypeType = enterClass("java.lang.invoke.MethodType");
         methodHandlesType = enterClass("java.lang.invoke.MethodHandles");
-        methodHandleLookupType = enterClass("java.lang.invoke.MethodHandleLookup");
+        methodHandleLookupType = enterClass("java.lang.invoke.MethodHandles$Lookup");
         methodHandleProxies = enterClass("java.lang.invoke.MethodHandleProxies");
         polymorphicSignatureType = enterClass("java.lang.invoke.MethodHandle$PolymorphicSignature");
         errorType = enterClass("java.lang.Error");
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Aug 08 13:42:09 2011 +0100
@@ -2712,7 +2712,7 @@
         //is a no-op (as this has been taken care during method applicability)
         checkSAMCompatible(inferenceContext, to, List.of(returnType),
                 samDesc.getParameterTypes(), mtype.getThrownTypes(), allowBoxing, true);
-        return to;
+        return tree.targetType = to;
     }
 
     /**
@@ -4087,6 +4087,9 @@
             if (that.sym == null) {
                 that.sym = new MethodSymbol(0, names.lambda, syms.unknownType, syms.noSymbol);
             }
+            if (that.targetType == null) {
+                that.targetType = syms.unknownType;
+            }
         }
     }
     // </editor-fold>
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Mon Aug 08 13:42:09 2011 +0100
@@ -26,20 +26,22 @@
 package com.sun.tools.javac.comp;
 
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
-import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.List;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.tree.JCTree.*;
+
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
-import com.sun.tools.javac.util.List;
-
-import java.util.Map;
-import java.util.HashMap;
-
-import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.tree.JCTree.*;
-import com.sun.tools.javac.code.Type.*;
-import java.util.LinkedHashMap;
 
 /** This pass desugars lambda expressions into static methods
  *
@@ -60,6 +62,9 @@
         return instance;
     }
 
+    /** use indy calls to create instances of SAM types */
+    boolean useIndy;
+
     /** current lambda translation context */
     LambdaTranslationContext context = null;
 
@@ -67,10 +72,12 @@
     private ListBuffer<JCTree> translatedLambdas;
 
     /** map from lambda trees to translation contexts */
-    private Map<JCTree, LambdaTranslationContext> contextMap = new HashMap<JCTree, LambdaTranslationContext>();
+    private Map<JCTree, TranslationContext> contextMap = new HashMap<JCTree, TranslationContext>();
     
     protected LambdaToMethod(Context context) {
         super(context);
+        Options options = Options.instance(context);
+        useIndy = options.isSet("useIndy");
     }
 
     @Override
@@ -91,7 +98,7 @@
 
     @Override
     public void visitLambda(JCLambda tree) {
-        LambdaTranslationContext localContext = contextMap.get(tree);
+        LambdaTranslationContext localContext = (LambdaTranslationContext)contextMap.get(tree);
         LambdaTranslationContext prevContext = context;
 
         //Step One:
@@ -127,12 +134,12 @@
 
             //prepend synthetic args to translated lambda method signature
             MethodType lambdaType = (MethodType)types.findSAM(tree.targetType).getTargetType();
-            localContext.lambdaMethodSymbol.type = lambdaType = types.createMethodTypeWithParameters(lambdaType, TreeInfo.types(syntheticParams.toList()));
+            localContext.translatedSym.type = lambdaType = types.createMethodTypeWithParameters(lambdaType, TreeInfo.types(syntheticParams.toList()));
 
             //create method declaration hoisting the lambda body
             JCBlock body = translate(makeLambdaBody(tree));
             JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(STATIC | SYNTHETIC),
-                    localContext.lambdaMethodSymbol.name,
+                    localContext.translatedSym.name,
                     make.QualIdent(lambdaType.getReturnType().tsym),
                     List.<JCTypeParameter>nil(),
                     syntheticParams.toList(),
@@ -141,7 +148,7 @@
                         make.Types(tree.sym.type.getThrownTypes()),
                     body,
                     null);
-            lambdaDecl.sym = (MethodSymbol)localContext.lambdaMethodSymbol;
+            lambdaDecl.sym = (MethodSymbol)localContext.translatedSym;
             lambdaDecl.type = lambdaType;
 
             //translate lambda body
@@ -163,10 +170,6 @@
         //1) reference to enclosing contexts captured by the lambda expression
         //2) enclosing locals captured by the lambda expression
 
-        JCMemberReference mref = make.Reference(ReferenceMode.INVOKE, localContext.lambdaMethodSymbol.name, make.QualIdent(localContext.lambdaMethodSymbol.owner), null, null);
-        mref.sym = localContext.lambdaMethodSymbol;
-        mref.type = tree.targetType;
-
         ListBuffer<JCExpression> syntheticInits = ListBuffer.lb();
 
         //append reference to enclosing contexts
@@ -185,11 +188,184 @@
             syntheticInits.append((JCExpression)captured_local);
         }
 
-        //generate method handle wrapper
-        result = makeMethodHandleWrapperProxy(mref,
-                                              tree.targetType,
-                                              translate(syntheticInits.toList()),
-                                              localContext.isRecursive());
+        if (useIndy) {
+
+            //first determine the static bsm args
+            List<Object> bsm_staticArgs = List.of(
+                tree.targetType.tsym,
+                new Pool.MemberReference(ClassFile.REF_invokeStatic, localContext.translatedSym));
+
+            //then, determine the arguments to the indy call
+            List<JCExpression> indy_args = List.of(Bool(localContext.isRecursive()),
+                    Array(syms.objectType, translate(syntheticInits.toList()).toArray(new JCExpression[syntheticInits.size()])));
+
+            //finally, compute the type of the indy call
+            MethodType indyType =
+                    new MethodType(List.of(syms.booleanType, new ArrayType(syms.objectType, syms.arrayClass)),
+                                   types.erasure(tree.targetType),
+                                   List.<Type>nil(),
+                                   syms.methodClass);
+
+            //build a sam instance using an indy call to the meta-factory
+            result = makeIndyCall(tree, syms.proxyHelper, names.metaFactory, bsm_staticArgs, indyType, indy_args);
+        } else {
+            //build a method reference AST node to the newly translated lambda
+            JCMemberReference mref = make.Reference(ReferenceMode.INVOKE, localContext.translatedSym.name, make.QualIdent(localContext.translatedSym.owner), null, null);
+            mref.sym = localContext.translatedSym;
+            mref.type = tree.targetType;
+
+            //build a sam instance using dynamic proxies
+            result = makeMethodHandleWrapperProxy(mref,
+                                                  tree.targetType,
+                                                  translate(syntheticInits.toList()),
+                                                  localContext.isRecursive());
+        }
+    }
+
+    @Override
+    public void visitReference(JCMemberReference tree) {
+        if (useIndy) {
+            ReferenceTranslationContext localContext = (ReferenceTranslationContext)contextMap.get(tree);
+
+            //first determine the method symbol to be used to generate the sam instance
+            //this is either the method reference symbol, or the bridged reference symbol
+            Symbol refSym = localContext.needsBridge() ?
+                bridgeMemberReference(tree, localContext) :
+                tree.sym;
+
+            //second, determine the static bsm args
+            List<Object> bsm_staticArgs = List.of(
+                tree.targetType.tsym,
+                new Pool.MemberReference(localContext.referenceKind(), refSym));
+
+            //third, determine the arguments to the indy call
+            List<JCExpression> indy_args = List.of(Bool(false),
+                    localContext.isInstanceRef() ? Array(syms.objectType, tree.getQualifierExpression()) : Null());
+
+            //finally, compute the type of the indy call
+            MethodType indyType =
+                    new MethodType(List.of(syms.booleanType, new ArrayType(syms.objectType, syms.arrayClass)),
+                                   types.erasure(tree.targetType),
+                                   List.<Type>nil(),
+                                   syms.methodClass);
+
+            //build a sam instance using an indy call to the meta-factory
+            result = makeIndyCall(tree, syms.proxyHelper, names.metaFactory, bsm_staticArgs, indyType, indy_args);
+
+            //if we had a static reference with non-static qualifier, add a let
+            //expression to force the evaluation of the qualifier expr
+            if (localContext.needsReceiverEval()) {
+                VarSymbol rec = new VarSymbol(0, names.fromString("rec$"), tree.getQualifierExpression().type, localContext.owner);
+                JCVariableDecl recDef = make.VarDef(rec, tree.getQualifierExpression());
+                result = make.LetExpr(recDef, result).setType(types.erasure(tree.targetType));
+            }
+        } else {
+            //translate using either dynamic proxies or MethodHandleProxies
+            super.visitReference(tree);
+        }
+    }
+
+    /**
+     * Bridges a member reference - this is needed whenever the signature of the
+     * underlying reference symbol does not match with the signature of the target
+     * sam descriptor. In such cases a bridge method is added so that the signature
+     * of the bridge method will match the signature of the target sam descriptor.
+     * The body of the bridge will simply contain a method/constructor call
+     * to the symbol associated with the method reference to be bridged.
+     */
+    Symbol bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
+        Type samDesc = types.findSAM(tree.targetType).getTargetType();
+
+        //generate the parameter list for the bridged member reference - the
+        //bridge signature will match the signature of the target sam descriptor
+        ListBuffer<JCExpression> args = ListBuffer.lb();
+        ListBuffer<JCVariableDecl> params = ListBuffer.lb();
+        int i = 0;
+        for (Type p : samDesc.getParameterTypes()) {
+            VarSymbol vsym = new VarSymbol(0, names.fromString("x$" + i), p, localContext.translatedSym);
+            params.append(make.VarDef(vsym, null));
+            if (!localContext.isUnbound() || i != 0) {
+                args.append(make.Ident(vsym));
+            }
+            i++;
+        }
+        //an extra argument is prepended to the signature of the bridge in case
+        //the member reference is an instance method reference (in which case
+        //the receiver expression is passed to the bridge itself).
+        if (localContext.isInstanceRef()) {
+            VarSymbol vsym = new VarSymbol(0, names.fromString("rec$" + i), tree.getQualifierExpression().type, localContext.translatedSym);
+            params.prepend(make.VarDef(vsym, null));
+        }
+
+        //generate the bridge method declaration
+        JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(STATIC | SYNTHETIC),
+                localContext.translatedSym.name,
+                make.QualIdent(samDesc.getReturnType().tsym),
+                List.<JCTypeParameter>nil(),
+                params.toList(),
+                tree.sym.type.getThrownTypes() == null ?
+                    List.<JCExpression>nil() :
+                    make.Types(tree.sym.type.getThrownTypes()),
+                null,
+                null);
+        bridgeDecl.sym = (MethodSymbol)localContext.translatedSym;
+        bridgeDecl.type = localContext.translatedSym.type = types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
+            
+        //bridge method body generation - this can be either a method call or a
+        //new instance creation expression, depending on the member reference kind
+        if (tree.getMode() == ReferenceMode.INVOKE) {
+            //determine the receiver of the bridged method call - the receiver can be
+            //either the synthetic receiver parameter or a type qualifier; the original
+            //qualifier expression is never used here, as it might refer to symbols
+            //not available in the static context of the bridge
+            JCExpression qualifier = null;
+            if (localContext.isUnbound() || localContext.isInstanceRef()) {
+                qualifier = make.Ident(params.first());
+            } else {
+                Assert.check(tree.sym.isStatic());
+                qualifier = make.Type(tree.sym.owner.type);
+            }
+
+            //create the qualifier expression
+            JCFieldAccess select = make.Select(qualifier, tree.sym.name);
+            select.sym = tree.sym;
+            select.type = types.memberType(tree.targetType, tree.sym);
+
+            //create the method call expression
+            JCMethodInvocation apply = make.Apply(List.<JCExpression>nil(), select, args.toList(), false);
+            apply.type = samDesc.getReturnType();
+            if ((tree.sym.flags() & VARARGS) != 0) {
+                apply.varargsElement = types.elemtype(tree.sym.type.getParameterTypes().last());
+            }
+
+            //the body is either a return expression containing a method call,
+            //or the method call itself, depending on whether the return type of
+            //the bridge is non-void/void.
+            bridgeDecl.body = make.Block(0, List.<JCStatement>of((apply.type.tag != TypeTags.VOID) ?
+                make.Return(apply) :
+                make.Exec(apply)));
+        } else {
+            //the enclosing expression is either 'null' (no enclosing type) or
+            //set to the first bridge synthetic parameter
+            JCExpression encl = localContext.isUnbound() ? make.Ident(params.first()) : null;
+
+            //create the instance creation expression
+            JCNewClass newClass = make.NewClass(encl,
+                                                List.<JCExpression>nil(),
+                                                make.Type(types.erasure(tree.sym.owner.type)),
+                                                args.toList(),
+                                                null);
+            newClass.constructor = tree.sym;
+            newClass.constructorType = types.memberType(tree.sym.owner.type, tree.sym);
+            newClass.type = types.erasure(tree.sym.owner.type);
+
+            //the body is alays a return expression containing an instance creation
+            //expression (as a constructor reference cannot be void)
+            bridgeDecl.body = make.Block(0, List.<JCStatement>of(make.Return(newClass)));
+        }
+
+        translatedLambdas = translatedLambdas.prepend(bridgeDecl);
+        return bridgeDecl.sym;
     }
 
     @Override
@@ -359,11 +535,16 @@
         }
 
         @Override
+        public void visitReference(JCMemberReference tree) {
+            contextMap.put(tree, new ReferenceTranslationContext(tree, lambdaName(), owner(), frameStack.size() - 1, context));
+        }
+
+        @Override
         public void visitLambda(JCLambda tree) {
             LambdaTranslationContext prevContext = context;
             List<Frame> prevStack = frameStack;
             try {
-                context = new LambdaTranslationContext(lambdaName(), owner(), self, frameStack.size() - 1, context);
+                context = new LambdaTranslationContext(tree, lambdaName(), owner(), self, frameStack.size() - 1, context);
                 frameStack = frameStack.prepend(new Frame(tree));
                 for (JCVariableDecl param : tree.params) {
                     context.addParam(param.sym);
@@ -386,19 +567,21 @@
                 if (tree.sym.kind == VAR &&
                         tree.sym.owner.kind == MTH &&
                         tree.type.constValue() == null) {
-                    LambdaTranslationContext localContext = context;
+                    TranslationContext localContext = context;
                     while (localContext != null) {
+                        if (localContext.tree.getTag() != JCTree.LAMBDA) continue;
                         JCTree block = capturedDecl(localContext.depth, tree.sym);
                         if (block == null) break;
-                        localContext.addCapturedVarIfNeeded(tree.sym);
+                        ((LambdaTranslationContext)localContext).addCapturedVarIfNeeded(tree.sym);
                         localContext = localContext.prev;
                     }
                 } else if (tree.sym.owner.kind == TYP) {
-                    LambdaTranslationContext localContext = context;
+                    TranslationContext localContext = context;
                     while (localContext != null) {
+                        if (localContext.tree.getTag() != JCTree.LAMBDA) continue;
                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
                         if (clazz == null) break;
-                        localContext.addEnclosingRefIfNeeded(clazz.sym);
+                        ((LambdaTranslationContext)localContext).addEnclosingRefIfNeeded(clazz.sym);
                         localContext = localContext.prev;
                     }
                 }
@@ -408,11 +591,12 @@
         @Override
         public void visitSelect(JCFieldAccess tree) {
             if (context != null && lambdaSymbolFilter.accepts(tree.sym) && tree.name == names._this) {
-                LambdaTranslationContext localContext = context;
+                TranslationContext localContext = context;
                 while (localContext != null) {
+                    if (localContext.tree.getTag() != JCTree.LAMBDA) continue;
                     JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
                     if (clazz == null) break;
-                    localContext.addEnclosingRefIfNeeded(clazz.sym);
+                    ((LambdaTranslationContext)localContext).addEnclosingRefIfNeeded(clazz.sym);
                     localContext = localContext.prev;
                 }
                 scan(tree.selected);
@@ -470,28 +654,50 @@
     }
 
     /**
+     * This class is used to store important information regarding translation of
+     * lambda expression/method references (see subclasses).
+     */
+    static class TranslationContext<T extends JCTree> {
+
+        /** the underlying (untranslated) tree */
+        T tree;
+
+        /** the synthetic symbol for the static method hoisting the translated lambda/mref */
+        Symbol translatedSym;
+
+        /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
+        Symbol owner;
+
+        /** the depth of this lambda expression in the frame stack */
+        int depth;
+
+        /** the enclosing translation context (set for nested lambdas/mref) */
+        TranslationContext prev;
+
+        TranslationContext(T tree,
+                           Name name,
+                           Symbol owner,
+                           int depth,
+                           TranslationContext prev) {
+            this.translatedSym = new MethodSymbol(SYNTHETIC | STATIC, name, null, owner.outermostClass());
+            this.tree = tree;
+            this.owner = owner;
+            this.depth = depth;
+            this.prev = prev;
+        }
+    }
+
+    /**
      * This class retains all the useful information about a lambda expression;
      * the contents of this class are filled by the LambdaAnalyzer visitor,
      * and the used by the main translation routines in order to adjust references
      * to captured locals/members, etc.
      */
-    class LambdaTranslationContext {
-
-        /** the synthetic symbol for the static method hoisting the translated lambda */
-        Symbol lambdaMethodSymbol;
-
+    class LambdaTranslationContext extends TranslationContext<JCLambda> {
+        
         /** variable in the enclosing context to which this lambda is assigned */
         Symbol self;
-
-        /** points to the adjusted enclosing scope in which this lambda expression occurs */
-        Symbol owner;
-
-        /** the depth of this lambda expression in the frame stack */
-        int depth;
-
-        /** the enclosing translation context (set for nested lambdas) */
-        LambdaTranslationContext prev;
-
+        
         /** map from original to translated lambda parameters */
         Map<Symbol, Symbol> lambdaParams = new LinkedHashMap<Symbol, Symbol>();
 
@@ -504,16 +710,14 @@
         /** map from class symbols to translated synthetic parameters (for captured member access) */
         Map<Symbol, Symbol> capturedThis = new LinkedHashMap<Symbol, Symbol>();
 
-        LambdaTranslationContext(Name name,
-                                        Symbol owner,
-                                        Symbol self,
-                                        int depth,
-                                        LambdaTranslationContext prev) {
-            this.lambdaMethodSymbol = new MethodSymbol(SYNTHETIC | STATIC, name, null, owner.outermostClass());
-            this.owner = owner;
+        LambdaTranslationContext(JCLambda lambdaTree,
+                           Name name,
+                           Symbol owner,
+                           Symbol self,
+                           int depth,
+                           TranslationContext prev) {
+            super(lambdaTree, name, owner, depth, prev);
             this.self = self;
-            this.depth = depth;
-            this.prev = prev;
         }
 
         /**
@@ -522,7 +726,7 @@
         void addCapturedVarIfNeeded(Symbol sym) {
             if (!capturedLocals.containsKey(sym)) {
                 Symbol trans_loc =
-                        new VarSymbol(PARAMETER | SYNTHETIC, sym.name, sym.type, lambdaMethodSymbol);
+                        new VarSymbol(PARAMETER | SYNTHETIC, sym.name, sym.type, translatedSym);
                 capturedLocals.put(sym, trans_loc);
             }
         }
@@ -534,7 +738,7 @@
             if (!capturedThis.containsKey(csym)) {
                 VarSymbol _encl$i = new VarSymbol(PARAMETER | SYNTHETIC,
                             names.fromString("encl$" + capturedThis.size()),
-                            csym.type, lambdaMethodSymbol);
+                            csym.type, translatedSym);
                 capturedThis.put(csym, _encl$i);
             }
         }
@@ -545,7 +749,7 @@
          */
         void addLocalVar(Symbol sym) {
             Symbol trans_loc =
-                    new VarSymbol(SYNTHETIC, sym.name, sym.type, lambdaMethodSymbol);
+                    new VarSymbol(SYNTHETIC, sym.name, sym.type, translatedSym);
             lambdaLocals.put(sym, trans_loc);
         }
 
@@ -555,7 +759,7 @@
          */
         void addParam(Symbol sym) {
             Symbol trans_param =
-                    new VarSymbol(PARAMETER | SYNTHETIC, sym.name, sym.type, lambdaMethodSymbol);
+                    new VarSymbol(PARAMETER | SYNTHETIC, sym.name, sym.type, translatedSym);
             lambdaParams.put(sym, trans_param);
         }
 
@@ -567,4 +771,76 @@
                     capturedLocals.containsKey(self);
         }
     }
+
+    /**
+     * This class retains all the useful information about a method reference;
+     * the contents of this class are filled by the LambdaAnalyzer visitor,
+     * and the used by the main translation routines in order to adjust method
+     * references (i.e. in case a bridge is needed)
+     */
+    class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
+
+        ReferenceTranslationContext(JCMemberReference refTree,
+                           Name name,
+                           Symbol owner,
+                           int depth,
+                           TranslationContext prev) {
+            super(refTree, name, owner, depth, prev);
+        }
+
+        /**
+         * Get the opcode associated with this method reference
+         */
+        int referenceKind() {
+            Symbol refSym = needsBridge() ? translatedSym : tree.sym;
+            if (tree.getQualifierExpression().getTag() == JCTree.IDENT &&
+                ((JCIdent)tree.getQualifierExpression()).name == names._super) {
+                return Pool.MemberReference.specialRefKind(refSym.isConstructor());
+            } else if (refSym.isConstructor()) {
+                return Pool.MemberReference.specialRefKind(refSym.isConstructor());
+            } else {
+                return Pool.MemberReference.methodRefKind(refSym.isStatic(), refSym.enclClass().isInterface());
+            }
+        }
+
+        /**
+         * Does this reference needs a bridge (i.e. in case the signature
+         * of the referenced symbol does not match the signature of the sam
+         * descriptor
+         */
+        boolean needsBridge() {
+            Type samDesc = types.findSAM(tree.targetType).getTargetType();
+            return !types.hasSameArgs(types.erasure(samDesc), types.erasure(tree.sym.type));
+        }
+
+        /**
+         * Is this an unbound reference? An unbound reference is either a
+         * (i) instance method reference with static qualifier or a (ii) inner
+         * class constructor reference
+         */
+        boolean isUnbound() {
+            return tree.getMode() == ReferenceMode.INVOKE ?
+                (!tree.sym.isStatic() && TreeInfo.isStaticSelector(tree.getQualifierExpression(), names)) :
+                (tree.sym.owner.type.getEnclosingType() != Type.noType);
+        }
+
+        /**
+         * Is this an instance method reference with a non-static qualifier?
+         */
+        boolean isInstanceRef() {
+            return tree.getMode() == ReferenceMode.INVOKE &&
+                    !TreeInfo.isStaticSelector(tree.getQualifierExpression(), names) &&
+                    !tree.sym.isStatic();
+        }
+
+        /**
+         * Is this a static reference with a non-static qualifier (which needs
+         * to be evaluated separately) ?
+         */
+        boolean needsReceiverEval() {
+            return tree.getMode() == ReferenceMode.INVOKE &&
+                !TreeInfo.isStaticSelector(tree.getQualifierExpression(), names) &&
+                tree.sym.isStatic();
+        }
+    }
 }
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java	Mon Aug 08 13:42:09 2011 +0100
@@ -26,9 +26,10 @@
 package com.sun.tools.javac.comp;
 
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
-import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.JCDiagnostic.*;
 
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.tree.JCTree.*;
@@ -127,7 +128,7 @@
         qualifier.sym = msym;
         qualifier.type = msym.type;
 
-        List<JCExpression> proxyCallArgs = List.of(classLiteral(type), mref,
+        List<JCExpression> proxyCallArgs = List.of(Class(type), mref,
                 make.Literal(TypeTags.BOOLEAN, recursive ? 1 : 0).setType(syms.booleanType));
         if (args != null) {
             proxyCallArgs = proxyCallArgs.appendList(args);
@@ -138,6 +139,61 @@
         return proxyCall;
     }
 
+    JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
+        List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                                         syms.stringType,
+                                         syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
+
+        Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
+                bsmName, bsm_staticArgs, List.<Type>nil());
+
+        DynamicMethodSymbol dynSym =
+                new DynamicMethodSymbol(names.lambda,
+                                        syms.noSymbol,
+                                        bsm.isStatic() ? ClassFile.REF_invokeStatic : ClassFile.REF_invokeVirtual,
+                                        (MethodSymbol)bsm,
+                                        indyType,
+                                        staticArgs.toArray());
+
+        JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
+        qualifier.sym = dynSym;
+        qualifier.type = indyType.getReturnType();
+
+        JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs, false);
+        proxyCall.type = indyType.getReturnType();
+        return proxyCall;
+    }
+    //where
+        List<Type> bsmStaticArgToTypes(List<Object> args) {
+            ListBuffer<Type> argtypes = ListBuffer.lb();
+            for (Object arg : args) {
+                argtypes.append(bsmStaticArgToType(arg));
+            }
+            return argtypes.toList();
+        }
+
+        Type bsmStaticArgToType(Object arg) {
+            Assert.checkNonNull(arg);
+            if (arg instanceof ClassSymbol) {
+                return syms.classType;
+            } else if (arg instanceof Integer) {
+                return syms.intType;
+            } else if (arg instanceof Long) {
+                return syms.longType;
+            } else if (arg instanceof Float) {
+                return syms.floatType;
+            } else if (arg instanceof Double) {
+                return syms.doubleType;
+            } else if (arg instanceof String) {
+                return syms.stringType;
+            } else if (arg instanceof Pool.MemberReference) {
+                return syms.methodHandleType;
+            } else {
+                Assert.error("bad static arg " + arg.getClass());
+                return null;
+            }
+        }
+
     /**
      * Create a wrapper instance around a method handle using 292 API
      * (MethodHandleProxies). This variant is slightly more unstable than
@@ -157,7 +213,7 @@
         qualifier.type = msym.type;
 
         JCMethodInvocation proxyCall =
-                make.Apply(List.<JCExpression>nil(), qualifier, List.of(classLiteral(type), mref), false);
+                make.Apply(List.<JCExpression>nil(), qualifier, List.of(Class(type), mref), false);
         proxyCall.type = types.erasure(qualifier.type);
         return proxyCall;
     }
@@ -165,7 +221,7 @@
     /**
      * Create a class literal as in 'Foo.class'
      */
-    JCExpression classLiteral(Type t) {
+    JCExpression Class(Type t) {
         Type erasedClassType = types.erasure(syms.classType);
         JCFieldAccess classLit =
                 make.Select(make.Type(types.erasure(t)), names._class);
@@ -173,4 +229,16 @@
                         Flags.STATIC | Flags.PUBLIC | Flags.FINAL, names._class, erasedClassType, t.tsym);
         return classLit.setType(erasedClassType);
     }
+
+    JCExpression Null() {
+        return make.Literal(TypeTags.BOT, null).setType(syms.botType);
+    }
+
+    JCExpression Bool(boolean b) {
+        return make.Literal(TypeTags.BOOLEAN, b ? 1 : 0).setType(syms.booleanType);
+    }
+
+    JCExpression Array(Type elemtype, JCExpression... elems) {
+        return make.NewArray(make.Type(elemtype), List.<JCExpression>nil(), List.from(elems)).setType(new ArrayType(elemtype, syms.arrayClass));
+    }
 }
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Mon Aug 08 13:42:09 2011 +0100
@@ -26,6 +26,8 @@
 package com.sun.tools.javac.jvm;
 
 import java.io.*;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.Set;
 import java.util.HashSet;
 
@@ -137,6 +139,11 @@
      */
     ListBuffer<ClassSymbol> innerClassesQueue;
 
+    /** The bootstrap methods to be written in the corresponding class attribute
+     *  (one for each invokedynamic)
+     */
+    Map<MethodSymbol, Pool.MemberReference> bootstrapMethods;
+
     /** The log to use for verbose output.
      */
     private final Log log;
@@ -484,11 +491,27 @@
 
             if (value instanceof MethodSymbol) {
                 MethodSymbol m = (MethodSymbol)value;
-                poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0
-                          ? CONSTANT_InterfaceMethodref
-                          : CONSTANT_Methodref);
-                poolbuf.appendChar(pool.put(m.owner));
-                poolbuf.appendChar(pool.put(nameType(m)));
+                if (!m.isDynamic()) {
+                    poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0
+                              ? CONSTANT_InterfaceMethodref
+                              : CONSTANT_Methodref);
+                    poolbuf.appendChar(pool.put(m.owner));
+                    poolbuf.appendChar(pool.put(nameType(m)));
+                } else {
+                    //invokedynamic
+                    DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m;
+                    Pool.MemberReference handle = new Pool.MemberReference(dynSym.bsmKind, dynSym.bsm);
+                    bootstrapMethods.put(dynSym, handle);
+                    //init cp entries
+                    pool.put(names.BootstrapMethods);
+                    pool.put(handle);
+                    for (Object staticArg : dynSym.staticArgs) {
+                        pool.put(staticArg);
+                    }
+                    poolbuf.appendByte(CONSTANT_InvokeDynamic);
+                    poolbuf.appendChar(bootstrapMethods.size() - 1);
+                    poolbuf.appendChar(pool.put(nameType(dynSym)));
+                }
             } else if (value instanceof VarSymbol) {
                 VarSymbol v = (VarSymbol)value;
                 poolbuf.appendByte(CONSTANT_Fieldref);
@@ -934,6 +957,25 @@
         endAttr(alenIdx);
     }
 
+    /** Write "bootstrapMethods" attribute.
+     */
+    void writeBootstrapMethods() {
+        int alenIdx = writeAttr(names.BootstrapMethods);
+        databuf.appendChar(bootstrapMethods.size());
+        for (Map.Entry<MethodSymbol, Pool.MemberReference> entry : bootstrapMethods.entrySet()) {
+            DynamicMethodSymbol dsym = (DynamicMethodSymbol)entry.getKey();
+            //write BSM handle
+            databuf.appendChar(pool.get(entry.getValue()));
+            //write static args length
+            databuf.appendChar(dsym.staticArgs.length);
+            //write static args array
+            for (Object o : dsym.staticArgs) {
+                databuf.appendChar(pool.get(o));
+            }
+        }
+        endAttr(alenIdx);
+    }
+
     /** Write field symbol, entering all references into constant pool.
      */
     void writeField(VarSymbol v) {
@@ -1502,6 +1544,7 @@
         pool = c.pool;
         innerClasses = null;
         innerClassesQueue = null;
+        bootstrapMethods = new LinkedHashMap<MethodSymbol, Pool.MemberReference>();
 
         Type supertype = types.supertype(c.type);
         List<Type> interfaces = types.interfaces(c.type);
@@ -1599,6 +1642,12 @@
             writeInnerClasses();
             acount++;
         }
+
+        if (!bootstrapMethods.isEmpty()) {
+            writeBootstrapMethods();
+            acount++;
+        }
+
         endAttrs(acountIdx, acount);
 
         poolbuf.appendBytes(databuf.elems, 0, databuf.length);
--- a/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Mon Aug 08 13:42:09 2011 +0100
@@ -2113,6 +2113,8 @@
             result = res;
         } else if (sym.kind == VAR && sym.owner.kind == MTH) {
             result = items.makeLocalItem((VarSymbol)sym);
+        } else if (isInvokeDynamic(sym)) {
+            result = items.makeDynamicItem(sym);
         } else if ((sym.flags() & STATIC) != 0) {
             if (!isAccessSuper(env.enclMethod))
                 sym = binaryQualifier(sym, env.enclClass.type);
@@ -2160,8 +2162,13 @@
             result = items.
                 makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue());
         } else {
-            if (!accessSuper)
+            if (isInvokeDynamic(sym)) {
+                result = items.makeDynamicItem(sym);
+                return;
+            } else if (!accessSuper) {
                 sym = binaryQualifier(sym, tree.selected.type);
+            }
+
             if ((sym.flags() & STATIC) != 0) {
                 base.exec();
                 result = items.makeStaticItem(sym);
@@ -2180,6 +2187,10 @@
         }
     }
 
+    public boolean isInvokeDynamic(Symbol sym) {
+        return sym.kind == MTH && ((MethodSymbol)sym).isDynamic();
+    }
+
     public void visitReference(JCMemberReference tree) {
         Symbol refSym = tree.sym;
         final boolean isStatic = refSym.isStatic();
--- a/src/share/classes/com/sun/tools/javac/jvm/Items.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/Items.java	Mon Aug 08 13:42:09 2011 +0100
@@ -110,6 +110,13 @@
         return stackItem[Code.typecode(type)];
     }
 
+    /** Make an item representing a dynamically invoked method.
+     *  @param member   The represented symbol.
+     */
+    Item makeDynamicItem(Symbol member) {
+        return new DynamicItem(member);
+    }
+
     /** Make an item representing an indexed expression.
      *  @param type    The expression's type.
      */
@@ -469,6 +476,35 @@
         }
     }
 
+    /** An item representing a dynamic call site.
+     */
+    class DynamicItem extends StaticItem {
+        DynamicItem(Symbol member) {
+            super(member);
+        }
+
+        Item load() {
+            assert false;
+            return null;
+        }
+
+        void store() {
+            assert false;
+        }
+
+        Item invoke() {
+            // assert target.hasNativeInvokeDynamic();
+            MethodType mtype = (MethodType)member.erasure(types);
+            int rescode = Code.typecode(mtype.restype);
+            code.emitInvokedynamic(pool.put(member), mtype);
+            return stackItem[rescode];
+        }
+
+        public String toString() {
+            return "dynamic(" + member + ")";
+        }
+    }
+
     /** An item representing an instance variable or method.
      */
     class MemberItem extends Item {
--- a/src/share/classes/com/sun/tools/javac/jvm/Pool.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/Pool.java	Mon Aug 08 13:42:09 2011 +0100
@@ -32,6 +32,7 @@
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.util.Assert;
 
 /** An internal structure that corresponds to the constant pool of a classfile.
  *
@@ -100,7 +101,7 @@
      *  package.  Return the object's index in the pool.
      */
     public int put(Object value) {
-        if (value instanceof Symbol && !(value instanceof ClassSymbol))
+        if (value instanceof Symbol && !(value instanceof ClassSymbol) && !(value instanceof DynamicMethodSymbol))
             value = delegateSymbol((Symbol) value);
 //      assert !(value instanceof Type.TypeVar);
         Integer index = indices.get(value);
@@ -182,10 +183,10 @@
     public static class MemberReference {
         int refKind;  // e.g., ClassFile.REF_invokeStatic, etc.
         Symbol refSym;
-        MemberReference(int refKind, Symbol refSym) {
+        public MemberReference(int refKind, Symbol refSym) {
             this.refKind = refKind;
             this.refSym = refSym;
-            assert isConsistent();
+            Assert.check(isConsistent());
         }
         public boolean equals(Object other) {
             if (!(other instanceof MemberReference)) return false;
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Mon Aug 08 13:42:09 2011 +0100
@@ -1789,6 +1789,7 @@
         public JCExpression expr;
         public List<JCExpression> args;
         public List<JCExpression> typeargs;
+        public Type targetType;
         public Symbol sym;
 
         protected JCMemberReference(ReferenceMode mode, Name name, JCExpression expr, List<JCExpression> args, List<JCExpression> typeargs) {
--- a/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Mon Aug 08 13:42:09 2011 +0100
@@ -25,10 +25,11 @@
 
 package com.sun.tools.javac.tree;
 
-import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import java.io.*;
 import java.util.*;
 
+import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
+
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.code.*;
@@ -1100,28 +1101,22 @@
     }
 
     public void visitReference(JCMemberReference tree) {
-        switch (tree.mode) {
-        case INVOKE:
-            try {
-                printExpr(tree.expr);
-                print("#");
-                if (tree.typeargs != null) {
-                    print("<");
-                    printExprs(tree.typeargs);
-                    print(">");
-                }
-                print(tree.name);
-                if (tree.args != null) {
-                    print("(");
-                    printExprs(tree.args);
-                    print(")");
-                }
-            } catch (IOException e) {
-                throw new UncheckedIOException(e);
+        try {
+            printExpr(tree.expr);
+            print("#");
+            if (tree.typeargs != null) {
+                print("<");
+                printExprs(tree.typeargs);
+                print(">");
             }
-            break;
-        default:
-            throw new AssertionError("Unexpected reference kind: " + tree.mode);
+            print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new");
+            if (tree.args != null) {
+                print("(");
+                printExprs(tree.args);
+                print(")");
+            }
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
         }
     }
 
--- a/src/share/classes/com/sun/tools/javac/util/Names.java	Wed Jul 27 15:49:28 2011 -0700
+++ b/src/share/classes/com/sun/tools/javac/util/Names.java	Mon Aug 08 13:42:09 2011 +0100
@@ -88,6 +88,7 @@
     public final Name Exceptions;
     public final Name SourceFile;
     public final Name InnerClasses;
+    public final Name BootstrapMethods;
     public final Name Synthetic;
     public final Name Bridge;
     public final Name Defender;
@@ -121,6 +122,7 @@
     public final Name invoke;
     public final Name invokeWithArguments;
     public final Name makeProxy;
+    public final Name metaFactory;
     public final Name asInterfaceInstance;
     public final Name lookup;
     public final Name findStatic;
@@ -216,6 +218,7 @@
         Exceptions = fromString("Exceptions");
         SourceFile = fromString("SourceFile");
         InnerClasses = fromString("InnerClasses");
+        BootstrapMethods = fromString("BootstrapMethods");
         Synthetic = fromString("Synthetic");
         Bridge = fromString("Bridge");
         Defender = fromString("Defender");
@@ -251,6 +254,7 @@
         invoke = fromString("invoke");
         invokeWithArguments = fromString("invokeWithArguments");
         makeProxy = fromString("makeProxy");
+        metaFactory = fromString("metaFactory");
         asInterfaceInstance = fromString("asInterfaceInstance");
         lookup = fromString("lookup");
         fromMethodDescriptorString = fromString("fromMethodDescriptorString");