changeset 1133:a7e6203a332d

Add option to desugar lambda expressions into static methods *) Created top visitor for desugaring lambdas with basic translation support *) Created two subclasses of the above vistor, implementing different desugaring strategies for lambda expressions *) The new visitor (LambdaToMethod) can be enabled by using the -XDlambdaToMethod flag *) All regression tests pass with both translation strategies
author mcimadamore
date Thu, 14 Jul 2011 15:52:48 +0100
parents cb09efd9e158
children 305594037adf
files src/share/classes/com/sun/runtime/ProxyHelper.java src/share/classes/com/sun/tools/javac/comp/LambdaToInnerClass.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/comp/Unlambda.java src/share/classes/com/sun/tools/javac/main/JavaCompiler.java src/share/classes/com/sun/tools/javac/util/Names.java
diffstat 7 files changed, 1067 insertions(+), 346 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/runtime/ProxyHelper.java	Thu Jul 14 11:10:07 2011 +0100
+++ b/src/share/classes/com/sun/runtime/ProxyHelper.java	Thu Jul 14 15:52:48 2011 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2011 Sun Microsystems, Inc.  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
@@ -25,40 +25,88 @@
 
 package com.sun.runtime;
 
+import com.sun.tools.javac.util.Assert;
+
 import java.lang.reflect.Proxy;
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationHandler;
 import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
 
 /**
+ * Utility class to turn a method handle into a SAM instance
  *
- * @author mcimadamore
+ *  <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 ProxyHelper {
+    
+    public static <T> T makeProxy(final Class<T> sam, final MethodHandle mh) {
+        return makeProxy(sam, mh, false, (Object[])null);
+    }
+
     @SuppressWarnings("unchecked")
-    public static <T> T makeProxy(final Class<T> sam, final MethodHandle mh) {
-        return (T)Proxy.newProxyInstance(sam.getClassLoader(), new Class<?>[]{sam}, new InvocationHandler() {
-            @Override
-            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-                if (method.getDeclaringClass() == Object.class) {
-                    return dispatchObjectMethod(proxy, method, args);
-                }
-                else {
-                    return mh.invokeWithArguments(args);
-                }
+    public static <T> T makeProxy(final Class<T> sam, MethodHandle mh, boolean recursive, Object... captured) {
+        LambdaInvocationHandler handler = new LambdaInvocationHandler(mh);
+        Object proxy = (T)Proxy.newProxyInstance(sam.getClassLoader(), new Class<?>[]{sam}, handler);
+        handler.complete(recursive ? proxy : null, captured);
+        return (T)proxy;
+    }
+
+    /**
+     * Custom invocation handler to be used for dynamic proxy calls.
+     * This invocation handler starts off in the 'incomplete' state, meaning
+     * that the underlying method handle does not reflect the signature of
+     * the target SAM descriptor. Once the complete() method is called,
+     * the invocation handler becomes 'complete' - meaning that the
+     * invocation handler is ready to dispatch calls to the underlying method
+     * handle. This two-step setup process is necessary in order to deal with
+     * recursive lambdas: when we first create the dynamic proxy instance we
+     * have no way to pass the instance itself as a bound argument to the
+     * underlying method handle.
+     */
+    static class LambdaInvocationHandler implements InvocationHandler {
+
+        MethodHandle mh;
+        boolean complete = false;
+
+        LambdaInvocationHandler(MethodHandle mh) {
+           this.mh = mh;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            Assert.check(complete);
+            if (method.getDeclaringClass() == Object.class) {
+                return dispatchObjectMethod(proxy, method, args);
             }
+            else {
+                return mh.invokeWithArguments(args);
+            }
+        }
 
-            Object dispatchObjectMethod(Object proxy, Method method, Object... args) throws Throwable {
-                if (method.getName().equals("hashCode")) {
-                    return hashCode();
-                } else if (method.getName().equals("equals")) {
-                    return proxy == args[0];
-                } else if (method.getName().equals("toString")) {
-                    return toString();
-                } else {
-                    throw new AssertionError("Bad Object method " + method);
-                }
+        Object dispatchObjectMethod(Object proxy, Method method, Object... args) throws Throwable {
+            if (method.getName().equals("hashCode")) {
+                return hashCode();
+            } else if (method.getName().equals("equals")) {
+                return proxy == args[0];
+            } else if (method.getName().equals("toString")) {
+                return toString();
+            } else {
+                throw new AssertionError("Bad Object method " + method);
             }
-        });
+        }
+
+        void complete(Object proxy, Object... args) {
+            if (args != null) {
+                mh = MethodHandles.insertArguments(mh, 0, args);
+            }
+            if (proxy != null) {
+                mh = MethodHandles.insertArguments(mh, 0, proxy);
+            }
+            complete = true;
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToInnerClass.java	Thu Jul 14 15:52:48 2011 +0100
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.tree.*;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.List;
+
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.code.Type.*;
+
+/** This pass desugars lambda expressions into anonymous inner classes
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  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 LambdaToInnerClass extends LambdaTranslator {
+    protected static final Context.Key<LambdaToInnerClass> unlambdaKey =
+        new Context.Key<LambdaToInnerClass>();
+
+    public static LambdaToInnerClass instance(Context context) {
+        LambdaToInnerClass instance = context.get(unlambdaKey);
+        if (instance == null)
+            instance = new LambdaToInnerClass(context);
+        return instance;
+    }
+    
+    private Enter enter;
+    private MemberEnter memberEnter;
+
+    private JCClassDecl currentClass;
+    
+    protected LambdaToInnerClass(Context context) {
+        super(context);
+        enter = Enter.instance(context);
+        memberEnter = MemberEnter.instance(context);
+    }
+
+    @Override
+    public void visitClassDef(JCClassDecl tree) {
+        JCClassDecl prevClass = currentClass;
+        try {
+            currentClass = tree;
+            super.visitClassDef(tree);
+        }
+        finally {
+            currentClass = prevClass;
+        }
+    }
+
+    @Override
+    public void visitLambda(JCLambda tree) {
+        //create new anon class definition implementing SAM method
+        //   class <anon> extends SAMClass { ... }
+
+        ClassSymbol samClassSym = (ClassSymbol)tree.sym.owner;
+
+        Type superType = tree.targetType;
+
+        if (superType.isInterface()) {
+            ((ClassType)samClassSym.type).supertype_field = syms.objectType;
+            ((ClassType)samClassSym.type).interfaces_field = List.of(superType);
+        }
+        else {
+            ((ClassType)samClassSym.type).supertype_field = superType;
+        }
+
+        JCClassDecl samClassDecl = make.ClassDef(
+                make.Modifiers(samClassSym.flags_field),
+                names.empty,
+                List.<JCTypeParameter>nil(),
+                superType.isInterface() ? make.QualIdent(syms.objectType.tsym).setType(syms.objectType) : make.QualIdent(superType.tsym).setType(superType),
+                superType.isInterface() ? List.of(make.QualIdent(superType.tsym).setType(superType)) : List.<JCExpression>nil(),
+                null);
+
+        samClassDecl.sym = samClassSym;
+        samClassDecl.type = samClassSym.type;
+
+        JCMethodDecl samConstrDecl = makeDefaultConstructor(tree.pos(), samClassSym);
+
+        //create SAM method
+        //   R m(A1, A2 ... An) throws T1, T2 ... Tn {
+        //      [return] $mh.invoke(a1, a2, ... an);
+        //   }
+
+        MethodSymbol samMethSym = (MethodSymbol)tree.sym;
+
+
+        JCMethodDecl samMethodDecl = make.MethodDef(samMethSym, null);
+        samMethodDecl.params = tree.params;
+
+        samMethodDecl.body = makeLambdaBody(tree);
+        samClassDecl.defs = List.<JCTree>of(samConstrDecl, samMethodDecl);
+        samClassSym.members().enter(samConstrDecl.sym);
+        samClassSym.members().enter(samMethodDecl.sym);
+
+        JCNewClass newClass = make.NewClass(null,
+                List.<JCExpression>nil(),
+                make.QualIdent(superType.tsym),
+                List.<JCExpression>nil(),
+                samClassDecl);
+        newClass.constructor = samConstrDecl.sym;
+        newClass.setType(samClassSym.type);
+        enter.typeEnvs.get(samClassSym).tree = samClassDecl;
+        result = translate(newClass);
+    }
+
+    private JCMethodDecl makeDefaultConstructor(final DiagnosticPosition pos, final ClassSymbol owner) {
+
+        final MethodSymbol defaultConstrSym = new MethodSymbol(0, names.init, null, owner);
+        defaultConstrSym.type = new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass);
+
+        JCMethodDecl defaultConstr = (JCMethodDecl)memberEnter.DefaultConstructor(
+                make,
+                owner,
+                List.<Type>nil(),
+                List.<Type>nil(),
+                List.<Type>nil(),
+                defaultConstrSym.flags(),
+                false);
+        defaultConstr.sym = defaultConstrSym;
+        defaultConstr.type = defaultConstrSym.type;
+
+        class DefaultConstructorPatcher extends TreeScanner {
+            @Override
+            public void visitApply(JCMethodInvocation tree) {
+                super.visitApply(tree);
+                tree.type = syms.voidType; //super constructor call has void type
+            }
+            @Override
+            public void visitIdent(JCIdent tree) {
+                if (tree.name == names._super) {
+                    //set super constructor symbol and type
+                    tree.sym = syms.objectType.tsym.members().lookup(names.init).sym;
+                    tree.type = tree.sym.type;
+                }
+            }
+        }
+
+        new DefaultConstructorPatcher().scan(defaultConstr);
+        return defaultConstr;
+    }
+
+    @Override
+    public void visitIdent(JCIdent tree) {
+        if ((currentClass.sym.flags() & Flags.LAMBDA) != 0 &&
+                (tree.name == names._super ||
+                tree.name == names._this)) {
+            Type encl = tree.sym.owner.type;
+            result = make.Select(make.Type(types.erasure(encl)), tree.sym);
+        }
+        else if ((currentClass.sym.flags() & Flags.LAMBDA) != 0 &&
+                (tree.sym.kind == Kinds.VAR || tree.sym.kind == Kinds.MTH) &&
+                tree.sym.owner == syms.objectType.tsym) {
+            Type encl = currentClass.type.getEnclosingType();
+            while (encl != Type.noType && (encl.tsym.flags() & Flags.LAMBDA) != 0) {
+                encl = encl.getEnclosingType();
+            }
+            JCFieldAccess qualifiedThis =
+                    (JCFieldAccess)make.Select(make.Type(types.erasure(encl)),
+                                               names._this).setType(encl);
+            qualifiedThis.sym =  new VarSymbol(0, names._this, encl, encl.tsym);
+            result = make.Select(qualifiedThis, tree.sym);
+        }
+        else {
+            super.visitIdent(tree);
+        }
+    }
+
+    @Override
+    public void visitMethodDef(JCMethodDecl tree) {
+        if (tree.name == names.init &&
+                (currentClass.sym.flags() & Flags.LAMBDA) != 0) {
+            //skip synthetic constructor of lambda class
+            result = tree;
+            return;
+        }
+        super.visitMethodDef(tree);
+    }
+
+    @Override
+    public void visitVarDef(final JCVariableDecl tree) {
+        if (tree.sym.owner.kind == Kinds.MTH &&
+                tree.init != null &&
+                tree.init.getTag() == JCTree.LAMBDA) {
+
+            //if this is a local variable initialized with a lambda expression
+            //we need to check whether the variable is referenced from the lambda
+
+            super.visitVarDef(tree);
+            JCClassDecl c = ((JCNewClass)tree.init).def;
+            final VarSymbol selfRef = new VarSymbol(0, names._this, c.type, c.sym);
+
+            //references to variable under initialization from lambda body
+            //are automatically turned into references to a synthetic field
+            //of the desugared lambda class
+            
+            class LambdaVarInitPatcher extends TreeScanner {
+                boolean needsCapture = true;
+                @Override
+                public void visitIdent(JCIdent that) {
+                    if (tree.sym == that.sym) {
+                        needsCapture = true;
+                        that.sym = selfRef;
+                        that.name = selfRef.name;
+                    }
+                }
+            }
+            LambdaVarInitPatcher lvis = new LambdaVarInitPatcher();
+            lvis.scan(tree.init);
+        } else {
+            super.visitVarDef(tree);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Jul 14 15:52:48 2011 +0100
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.tree.*;
+import com.sun.tools.javac.util.*;
+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
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  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 LambdaToMethod extends LambdaTranslator {
+
+    protected static final Context.Key<LambdaToMethod> unlambdaKey =
+        new Context.Key<LambdaToMethod>();
+
+    public static LambdaToMethod instance(Context context) {
+        LambdaToMethod instance = context.get(unlambdaKey);
+        if (instance == null)
+            instance = new LambdaToMethod(context);
+        return instance;
+    }
+
+    /** current lambda translation context */
+    LambdaTranslationContext context = null;
+
+    /** list of static methods corresponding to translated lambda expression */
+    private ListBuffer<JCTree> translatedLambdas;
+
+    /** map from lambda trees to translation contexts */
+    private Map<JCTree, LambdaTranslationContext> contextMap = new HashMap<JCTree, LambdaTranslationContext>();
+    
+    protected LambdaToMethod(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void visitClassDef(JCClassDecl tree) {
+        if (tree.sym.owner.kind == PCK) {
+            new LambdaAnalyzer().scan(tree);
+            translatedLambdas = ListBuffer.lb();
+        }
+        super.visitClassDef(tree);
+        if (tree.sym.owner.kind == PCK) {
+            tree.defs = tree.defs.appendList(translatedLambdas.toList());
+            for (JCTree lambda : translatedLambdas) {
+                tree.sym.members().enter(((JCMethodDecl)lambda).sym);
+            }
+        }
+        result = tree;
+    }
+
+    @Override
+    public void visitLambda(JCLambda tree) {
+        LambdaTranslationContext localContext = contextMap.get(tree);
+        LambdaTranslationContext prevContext = context;
+
+        //Step One:
+        //translate the lambda expression into a static method. The signature of
+        //the static method is augmented with the following synthetic parameters:
+        //
+        //1) reference to enclosing contexts captured by the lambda expression
+        //2) enclosing locals captured by the lambda expression
+        //3) reference to self (for recursive lambdas only)
+        //
+        //As the lambda body is translated, all references to lambda locals,
+        //captured variables, enclosing members are adjusted accordingly
+        //to refer to the static method parameters (rather than i.e. acessing to
+        //captured members directly).
+        
+        try {
+            context = localContext;
+            //compute synthetic params
+            ListBuffer<JCVariableDecl> syntheticParams = ListBuffer.lb();
+            
+            //add encl$n if needed
+            for (Symbol thisSym : localContext.capturedThis.values()) {
+                syntheticParams.append(make.VarDef((VarSymbol)thisSym, null));
+            }
+            //add captured locals
+            for (Symbol fv : localContext.capturedLocals.values()) {
+                syntheticParams.append(make.at(tree.pos).VarDef((VarSymbol)fv, null));
+            }
+            //add lambda parameters
+            for (Symbol param : localContext.lambdaParams.values()) {
+                syntheticParams.append(make.at(tree.pos).VarDef((VarSymbol)param, null));
+            }
+
+            //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()));
+
+            //create method declaration hoisting the lambda body
+            JCBlock body = translate(makeLambdaBody(tree));
+            JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(STATIC | SYNTHETIC),
+                    localContext.lambdaMethodSymbol.name,
+                    make.QualIdent(lambdaType.getReturnType().tsym),
+                    List.<JCTypeParameter>nil(),
+                    syntheticParams.toList(),
+                    tree.sym.type.getThrownTypes() == null ?
+                        List.<JCExpression>nil() :
+                        make.Types(tree.sym.type.getThrownTypes()),
+                    body,
+                    null);
+            lambdaDecl.sym = (MethodSymbol)localContext.lambdaMethodSymbol;
+            lambdaDecl.type = lambdaType;
+
+            //translate lambda body
+            translatedLambdas = translatedLambdas.prepend(lambdaDecl);
+        }
+        finally {
+            context = prevContext;
+        }
+
+        //Step Two:
+        //now that we have generated a static method for the lambda expression,
+        //we can translate the lambda into a method reference pointing to the newly
+        //created static method.
+        //
+        //Note that we need to adjust the method handle so that it will match the
+        //signature of the SAM descriptor - this means that the method reference
+        //should be added the following synthetic arguments:
+        //
+        //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
+        for (Symbol sym : localContext.capturedThis.keySet()) {
+            VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
+                    names._this,
+                    sym.type, localContext.owner);
+            JCTree qualifiedThis = make.Select(make.QualIdent(sym), _this).setType(sym.type);
+            syntheticInits.append((JCExpression)qualifiedThis);
+        }
+
+        //add captured locals
+        for (Symbol fv : localContext.capturedLocals.keySet()) {
+            if (fv == localContext.self) continue;
+            JCTree captured_local = make.Ident(fv).setType(fv.type);
+            syntheticInits.append((JCExpression)captured_local);
+        }
+
+        //generate method handle wrapper
+        result = makeMethodHandleWrapperProxy(mref,
+                                              tree.targetType,
+                                              translate(syntheticInits.toList()),
+                                              localContext.isRecursive());
+    }
+
+    @Override
+    public void visitIdent(JCIdent tree) {
+        if (context == null || !lambdaSymbolFilter.accepts(tree.sym)) {
+            super.visitIdent(tree);
+        } else {
+            if (context.lambdaParams.containsKey(tree.sym)) {
+                Symbol translatedSym = context.lambdaParams.get(tree.sym);
+                result = make.Ident(translatedSym).setType(tree.type);
+            } else if (context.lambdaLocals.containsKey(tree.sym)) {
+                Symbol translatedSym = context.lambdaLocals.get(tree.sym);
+                result = make.Ident(translatedSym).setType(tree.type);
+            } else if (context.capturedLocals.containsKey(tree.sym)) {
+                Symbol translatedSym = context.capturedLocals.get(tree.sym);
+                result = make.Ident(translatedSym).setType(tree.type);
+            } else {
+                if (tree.sym.owner.kind == TYP) {
+                    for (Map.Entry<Symbol, Symbol> encl_entry : context.capturedThis.entrySet()) {
+                        if (tree.sym.isMemberOf((ClassSymbol)encl_entry.getKey(), types)) {
+                            result = make.Select(make.Ident(encl_entry.getValue()), tree.sym).setType(tree.type);
+                            return;
+                        }
+                    }
+                }
+                //access to untranslated symbols (i.e. compile-time constants,
+                //members defined inside the lambda body, etc.) )
+                super.visitIdent(tree);
+            }
+        }
+    }
+    
+    @Override
+    public void visitSelect(JCFieldAccess tree) {
+        if (context != null && lambdaSymbolFilter.accepts(tree.sym) &&
+                tree.name == names._this &&
+                context.capturedThis.containsKey(tree.selected.type.tsym)) {
+            JCExpression selected = translate(tree.selected);
+            result = make.Ident(context.capturedThis.get(selected.type.tsym));
+        } else {
+            super.visitSelect(tree);
+        }
+    }
+
+    /**
+     *  This is used to filter out those identifiers that needs to be adjusted
+     *  when translating away lambda expressions
+     */
+    Filter<Symbol> lambdaSymbolFilter = new Filter<Symbol>() {
+        public boolean accepts(Symbol sym) {
+            return !sym.isStatic() &&
+                    (sym.kind == VAR || sym.kind == MTH) &&
+                    sym.name != names._super && sym.name != names.init;
+        }
+    };
+
+    @Override
+    public void visitVarDef(JCVariableDecl tree) {
+        if (context != null && context.lambdaLocals.containsKey(tree.sym)) {
+            JCExpression init = translate(tree.init);
+            result = make.VarDef((VarSymbol)context.lambdaLocals.get(tree.sym), init);
+        } else {
+            super.visitVarDef(tree);
+        }
+    }
+
+    /**
+     * This visitor collects information about translation of a lambda expression.
+     * More specifically, it keeps track of the enclosing contexts and captured locals
+     * accessed by the lambda being translated (as well as other useful info).
+     */
+    class LambdaAnalyzer extends TreeScanner {
+
+        class Frame {
+            final JCTree tree;
+            List<Symbol> locals;
+
+            public Frame(JCTree tree) {
+                this.tree = tree;
+            }
+
+            void addLocal(Symbol sym) {
+                if (locals == null) {
+                    locals = List.nil();
+                }
+                locals = locals.prepend(sym);
+            }
+        }
+
+        /** current lambda translation context */
+        LambdaTranslationContext context = null;
+
+        /** the frame stack - used to reconstruct translation info about enclosing scopes */
+        List<Frame> frameStack = List.nil();
+
+        /** pending local variable with lambda initializer (can be used for recursion) */
+        Symbol self = null;
+
+        /** keep the count of lambda expression (used to generate unambiguous names) */
+        int lambdaCount = 0;
+
+        Name lambdaName() {
+            return names.lambda.append(names.fromString("$" + lambdaCount++));
+        }
+
+        @Override
+        public void visitClassDef(JCClassDecl tree) {
+            List<Frame> prevStack = frameStack;
+            try {
+                if (frameStack.nonEmpty() && frameStack.head.tree.getTag() == JCTree.LAMBDA) {
+                    tree.sym.owner = owner();
+                    ((ClassType)tree.sym.type).setEnclosingType(Type.noType);
+                }
+                frameStack = frameStack.prepend(new Frame(tree));
+                super.visitClassDef(tree);
+            }
+            finally {
+                frameStack = prevStack;
+            }
+        }
+
+        /**
+         * Return a valid owner given the current declaration stack
+         * (required to skip synthetic lambda symbols)
+         */
+        Symbol owner() {
+            for (Frame block : frameStack) {
+                switch (block.tree.getTag()) {
+                    case JCTree.CLASSDEF:
+                        return ((JCClassDecl)block.tree).sym;
+                    case JCTree.METHODDEF:
+                        return ((JCMethodDecl)block.tree).sym;
+                }
+            }
+            Assert.error();
+            return null;
+        }
+
+        /**
+         * Return the declaration corresponding to a symbol in the enclosing
+         * scope; the depth parameter is used to filter out symbols defined
+         * in nested scopes (which do not need to undergo capture).
+         */
+        JCTree capturedDecl(int depth, Symbol sym) {
+            int currentDepth = frameStack.size() - 1;
+            for (Frame block : frameStack) {
+                switch (block.tree.getTag()) {
+                    case JCTree.CLASSDEF:
+                        ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
+                        if (sym.isMemberOf(clazz, types)) {
+                            return currentDepth > depth ? null : block.tree;
+                        }
+                        break;
+                    case JCTree.BLOCK:
+                    case JCTree.METHODDEF:
+                    case JCTree.LAMBDA:
+                        if (block.locals != null && block.locals.contains(sym)) {
+                            return currentDepth > depth ? null : block.tree;
+                        }
+                        break;
+                    default:
+                        Assert.error("bad decl kind " + block.tree.getTag());
+                }
+                currentDepth--;
+            }
+            return null;
+        }
+
+        @Override
+        public void visitLambda(JCLambda tree) {
+            LambdaTranslationContext prevContext = context;
+            List<Frame> prevStack = frameStack;
+            try {
+                context = new LambdaTranslationContext(lambdaName(), owner(), self, frameStack.size() - 1, context);
+                frameStack = frameStack.prepend(new Frame(tree));
+                for (JCVariableDecl param : tree.params) {
+                    context.addParam(param.sym);
+                    frameStack.head.addLocal(param.sym);
+                }
+                contextMap.put(tree, context);
+                scan(tree.body);
+            }
+            finally {
+                context = prevContext;
+                frameStack = prevStack;
+            }
+        }
+
+        @Override
+        public void visitIdent(JCIdent tree) {
+            if (context == null || !lambdaSymbolFilter.accepts(tree.sym)) {
+                super.visitIdent(tree);
+            } else {
+                if (tree.sym.kind == VAR &&
+                        tree.sym.owner.kind == MTH &&
+                        tree.type.constValue() == null) {
+                    LambdaTranslationContext localContext = context;
+                    while (localContext != null) {
+                        JCTree block = capturedDecl(localContext.depth, tree.sym);
+                        if (block == null) break;
+                        localContext.addCapturedVarIfNeeded(tree.sym);
+                        localContext = localContext.prev;
+                    }
+                } else if (tree.sym.owner.kind == TYP) {
+                    LambdaTranslationContext localContext = context;
+                    while (localContext != null) {
+                        JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
+                        if (clazz == null) break;
+                        localContext.addEnclosingRefIfNeeded(clazz.sym);
+                        localContext = localContext.prev;
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void visitSelect(JCFieldAccess tree) {
+            if (context != null && lambdaSymbolFilter.accepts(tree.sym) && tree.name == names._this) {
+                LambdaTranslationContext localContext = context;
+                while (localContext != null) {
+                    JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
+                    if (clazz == null) break;
+                    localContext.addEnclosingRefIfNeeded(clazz.sym);
+                    localContext = localContext.prev;
+                }
+                scan(tree.selected);
+            } else {
+                super.visitSelect(tree);
+            }
+        }
+
+        @Override
+        public void visitBlock(JCBlock tree) {
+            List<Frame> prevStack = frameStack;
+            try {
+                if (frameStack.nonEmpty() && frameStack.head.tree.getTag() == JCTree.CLASSDEF) {
+                    frameStack = frameStack.prepend(new Frame(tree));
+                }
+                super.visitBlock(tree);
+            }
+            finally {
+                frameStack = prevStack;
+            }
+        }
+
+        @Override
+        public void visitMethodDef(JCMethodDecl tree) {
+            List<Frame> prevStack = frameStack;
+            try {
+                frameStack = frameStack.prepend(new Frame(tree));
+                super.visitMethodDef(tree);
+            }
+            finally {
+                frameStack = prevStack;
+            }
+        }
+
+        @Override
+        public void visitVarDef(JCVariableDecl tree) {
+            if (frameStack.head.tree.getTag() == JCTree.LAMBDA) {
+                context.addLocalVar(tree.sym);
+            }
+            Symbol prevSelf = self;
+            try {
+                if (tree.init != null &&
+                        tree.init.getTag() == JCTree.LAMBDA) {
+                    self = tree.sym;
+                }
+                if (tree.sym.owner.kind == MTH) {
+                    frameStack.head.addLocal(tree.sym);
+                }
+                super.visitVarDef(tree);
+            }
+            finally {
+                self = prevSelf;
+            }
+        }
+    }
+
+    /**
+     * 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;
+
+        /** 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>();
+
+        /** map from original to translated lambda locals */
+        Map<Symbol, Symbol> lambdaLocals = new LinkedHashMap<Symbol, Symbol>();
+
+        /** map from variables in enclosing scope to translated synthetic parameters */
+        Map<Symbol, Symbol> capturedLocals  = new LinkedHashMap<Symbol, Symbol>();
+
+        /** 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;
+            this.self = self;
+            this.depth = depth;
+            this.prev = prev;
+        }
+
+        /**
+         * Add a captured local variable to this context (if not captured yet)
+         */
+        void addCapturedVarIfNeeded(Symbol sym) {
+            if (!capturedLocals.containsKey(sym)) {
+                Symbol trans_loc =
+                        new VarSymbol(PARAMETER | SYNTHETIC, sym.name, sym.type, lambdaMethodSymbol);
+                capturedLocals.put(sym, trans_loc);
+            }
+        }
+
+        /**
+         * Add a captured enclosing scope to this context (if not captured yet)
+         */
+        void addEnclosingRefIfNeeded(ClassSymbol csym) {
+            if (!capturedThis.containsKey(csym)) {
+                VarSymbol _encl$i = new VarSymbol(PARAMETER | SYNTHETIC,
+                            names.fromString("encl$" + capturedThis.size()),
+                            csym.type, lambdaMethodSymbol);
+                capturedThis.put(csym, _encl$i);
+            }
+        }
+
+        /**
+         * Add a local variable to this context (i.e. variable declared inside the
+         * lambda associated with this context)
+         */
+        void addLocalVar(Symbol sym) {
+            Symbol trans_loc =
+                    new VarSymbol(SYNTHETIC, sym.name, sym.type, lambdaMethodSymbol);
+            lambdaLocals.put(sym, trans_loc);
+        }
+
+        /**
+         * Add a parameter to this context (a parameter of the lambda associated
+         * with this context)
+         */
+        void addParam(Symbol sym) {
+            Symbol trans_param =
+                    new VarSymbol(PARAMETER | SYNTHETIC, sym.name, sym.type, lambdaMethodSymbol);
+            lambdaParams.put(sym, trans_param);
+        }
+
+        /**
+         * Does the lambd associated with this context refers to itself?
+         */
+        boolean isRecursive() {
+            return self != null &&
+                    capturedLocals.containsKey(self);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java	Thu Jul 14 15:52:48 2011 +0100
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.tree.*;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.List;
+
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.code.Type.*;
+
+/** This is a common superclass for the lambda translators which factors
+ * some of the shared translation-related routines.
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  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 abstract class LambdaTranslator extends TreeTranslator {
+
+    protected Names names;
+    protected Symtab syms;
+    protected Resolve rs;
+    protected TreeMaker make;
+    protected Types types;
+    protected Env<AttrContext> attrEnv;
+
+    /** turns method handles into SAM instances using an internal API */
+    protected boolean useProxy;
+
+    protected LambdaTranslator(Context context) {
+        names = Names.instance(context);
+        syms = Symtab.instance(context);
+        rs = Resolve.instance(context);
+        make = TreeMaker.instance(context);
+        types = Types.instance(context);
+        Options options = Options.instance(context);
+        useProxy = options.isSet("useProxy");
+    }
+
+    public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
+        this.make = make;
+        this.attrEnv = env;
+        return translate(cdef);
+    }
+
+    @Override
+    public void visitReference(JCMemberReference tree) {
+        result = useProxy ?
+            makeMethodHandleWrapperProxy(tree, tree.type, null, false) :
+            makeMethodHandleWrapper292(tree, tree.type);
+    }
+
+    /**
+     * Generate desugared code for the lambda body; for expression lambdas
+     * a synthetic return statement might be added (if lambda can complete
+     * normally). Also, a return statement is added if the return type of
+     * he SAM descriptor is 'java.lang.Void' and the lambda expression is 'void'.
+     */
+    JCBlock makeLambdaBody(JCLambda tree) {
+        JCReturn defaultRet = null;
+        if (tree.canCompleteNormally &&
+                types.isSameType(tree.sym.type.getReturnType(), types.boxedClass(syms.voidType).type)) {
+            //there's no return statement and the lambda (possibly inferred)
+            //return type is java.lang.Void; sets the NEEDS_RETURN flag in
+            //order to tell code generation to emit a synthetic return statement
+            defaultRet = make.Return(make.Literal(TypeTags.BOT, null).setType(syms.botType));
+        }
+        JCBlock body = null;
+        if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION &&
+                tree.body.type != syms.voidType) {
+            body = make.Block(0, List.<JCStatement>of(make.Return((JCExpression)tree.body)));
+        } else {
+            switch (tree.body.getTag()) {
+                case JCTree.BLOCK: body = (JCBlock)tree.body; break;
+                default:
+                    JCStatement stat = make.Exec((JCExpression)tree.body);
+                    body = make.Block(0, List.<JCStatement>of(stat));
+            }
+        }
+        if (defaultRet != null) {
+            body.stats = body.stats.append(defaultRet);
+        }
+        return body;
+    }
+
+    /**
+     * Create a wrapper instance around a method handle using an internal API
+     * leveraging dynamic proxy classes. This routine handles recursive bodies
+     * (needed to support lambda that calls themselves) - as well as synthetic
+     * arguments that are bound to the underlying method handle.
+     */
+    JCExpression makeMethodHandleWrapperProxy(JCMemberReference mref, Type type, List<JCExpression> args, boolean recursive) {
+        List<Type> argtypes = List.of(types.erasure(syms.classType),
+                syms.methodHandleType, syms.booleanType, new ArrayType(syms.objectType, syms.arrayClass));
+        
+        Symbol msym = rs.resolveInternalMethod(mref.pos(), attrEnv, syms.proxyHelper,
+                names.makeProxy, argtypes, List.<Type>nil());
+
+        JCFieldAccess qualifier = make.Select(make.QualIdent(syms.proxyHelper.tsym), names.makeProxy);
+        qualifier.sym = msym;
+        qualifier.type = msym.type;
+
+        List<JCExpression> proxyCallArgs = List.of(classLiteral(type), mref,
+                make.Literal(TypeTags.BOOLEAN, recursive ? 1 : 0).setType(syms.booleanType));
+        if (args != null) {
+            proxyCallArgs = proxyCallArgs.appendList(args);
+        }
+        JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, proxyCallArgs, false);
+        proxyCall.varargsElement = syms.objectType;
+        proxyCall.type = types.erasure(qualifier.type);
+        return proxyCall;
+    }
+
+    /**
+     * Create a wrapper instance around a method handle using 292 API
+     * (MethodHandleProxies). This variant is slightly more unstable than
+     * the one using internal API - it also does not offer support for
+     * recursive method handles/bound arguments list.
+     */
+    JCExpression makeMethodHandleWrapper292(JCMemberReference mref, Type type) {
+        List<Type> argtypes = List.of(types.erasure(syms.classType),
+                syms.methodHandleType);
+
+        Symbol msym = rs.resolveInternalMethod(mref.pos(), attrEnv, syms.methodHandleProxies,
+                names.asInterfaceInstance, argtypes, List.<Type>nil());
+
+        JCFieldAccess qualifier =
+                make.Select(make.QualIdent(syms.methodHandleProxies.tsym), names.asInterfaceInstance);
+        qualifier.sym = msym;
+        qualifier.type = msym.type;
+
+        JCMethodInvocation proxyCall =
+                make.Apply(List.<JCExpression>nil(), qualifier, List.of(classLiteral(type), mref), false);
+        proxyCall.type = types.erasure(qualifier.type);
+        return proxyCall;
+    }
+
+    /**
+     * Create a class literal as in 'Foo.class'
+     */
+    JCExpression classLiteral(Type t) {
+        Type erasedClassType = types.erasure(syms.classType);
+        JCFieldAccess classLit =
+                make.Select(make.Type(types.erasure(t)), names._class);
+        classLit.sym = new VarSymbol(
+                        Flags.STATIC | Flags.PUBLIC | Flags.FINAL, names._class, erasedClassType, t.tsym);
+        return classLit.setType(erasedClassType);
+    }
+}
--- a/src/share/classes/com/sun/tools/javac/comp/Unlambda.java	Thu Jul 14 11:10:07 2011 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,318 +0,0 @@
-/*
- * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.tools.javac.comp;
-
-import com.sun.tools.javac.code.*;
-import com.sun.tools.javac.tree.*;
-import com.sun.tools.javac.util.*;
-import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
-import com.sun.tools.javac.util.List;
-
-import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.tree.JCTree.*;
-import com.sun.tools.javac.code.Type.*;
-
-/** This pass translates away lambda expressions
- *
- *  <p><b>This is NOT part of any API supported by Sun Microsystems.  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 Unlambda extends TreeTranslator {
-    protected static final Context.Key<Unlambda> unlambdaKey =
-        new Context.Key<Unlambda>();
-
-    public static Unlambda instance(Context context) {
-        Unlambda instance = context.get(unlambdaKey);
-        if (instance == null)
-            instance = new Unlambda(context);
-        return instance;
-    }
-
-    private Names names;
-    private Symtab syms;
-    private Resolve rs;
-    private Check chk;
-    private Enter enter;
-    private MemberEnter memberEnter;
-    private TreeMaker make;
-    private Types types;
-    private JCClassDecl currentClass;
-    private Env<AttrContext> attrEnv;
-    private boolean useProxy;
-
-    protected Unlambda(Context context) {
-        names = Names.instance(context);
-        syms = Symtab.instance(context);
-        rs = Resolve.instance(context);
-        chk = Check.instance(context);
-        enter = Enter.instance(context);
-        memberEnter = MemberEnter.instance(context);
-        make = TreeMaker.instance(context);
-        types = Types.instance(context);
-        Options options = Options.instance(context);
-        useProxy = options.isSet("useProxy");
-    }
-
-    public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
-        // note that this method does NOT support recursion.
-        this.make = make;
-        this.attrEnv = env;
-        return translate(cdef);
-    }
-
-    @Override
-    public void visitClassDef(JCClassDecl tree) {
-        JCClassDecl prevClass = currentClass;
-        try {
-            currentClass = tree;
-            super.visitClassDef(tree);
-        }
-        finally {
-            currentClass = prevClass;
-        }
-    }
-
-    @Override
-    public void visitLambda(JCLambda tree) {
-        //create new anon class definition implementing SAM method
-        //   class <anon> extends SAMClass { ... }
-
-        ClassSymbol samClassSym = (ClassSymbol)tree.sym.owner;
-
-        Type superType = tree.targetType;
-
-        if (superType.isInterface()) {
-            ((ClassType)samClassSym.type).supertype_field = syms.objectType;
-            ((ClassType)samClassSym.type).interfaces_field = List.of(superType);
-        }
-        else {
-            ((ClassType)samClassSym.type).supertype_field = superType;
-        }
-
-        JCClassDecl samClassDecl = make.ClassDef(
-                make.Modifiers(samClassSym.flags_field),
-                names.empty,
-                List.<JCTypeParameter>nil(),
-                superType.isInterface() ? make.QualIdent(syms.objectType.tsym).setType(syms.objectType) : make.QualIdent(superType.tsym).setType(superType),
-                superType.isInterface() ? List.of(make.QualIdent(superType.tsym).setType(superType)) : List.<JCExpression>nil(),
-                null);
-
-        samClassDecl.sym = samClassSym;
-        samClassDecl.type = samClassSym.type;
-
-        JCMethodDecl samConstrDecl = makeDefaultConstructor(tree.pos(), samClassSym);
-
-        //create SAM method
-        //   R m(A1, A2 ... An) throws T1, T2 ... Tn {
-        //      [return] $mh.invoke(a1, a2, ... an);
-        //   }
-
-        MethodSymbol samMethSym = (MethodSymbol)tree.sym;
-
-
-        JCMethodDecl samMethodDecl = make.MethodDef(samMethSym, null);
-        samMethodDecl.params = tree.params;
-
-        samMethodDecl.body = makeLambdaBody(tree);
-        samClassDecl.defs = List.<JCTree>of(samConstrDecl, samMethodDecl);
-        samClassSym.members().enter(samConstrDecl.sym);
-        samClassSym.members().enter(samMethodDecl.sym);
-
-        JCNewClass newClass = make.NewClass(null,
-                List.<JCExpression>nil(),
-                make.QualIdent(superType.tsym),
-                List.<JCExpression>nil(),
-                samClassDecl);
-        newClass.constructor = samConstrDecl.sym;
-        newClass.setType(samClassSym.type);
-        enter.typeEnvs.get(samClassSym).tree = samClassDecl;
-        result = translate(newClass);
-    }
-
-    private JCMethodDecl makeDefaultConstructor(final DiagnosticPosition pos, final ClassSymbol owner) {
-
-        final MethodSymbol defaultConstrSym = new MethodSymbol(0, names.init, null, owner);
-        defaultConstrSym.type = new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass);
-
-        JCMethodDecl defaultConstr = (JCMethodDecl)memberEnter.DefaultConstructor(
-                make,
-                owner,
-                List.<Type>nil(),
-                List.<Type>nil(),
-                List.<Type>nil(),
-                defaultConstrSym.flags(),
-                false);
-        defaultConstr.sym = defaultConstrSym;
-        defaultConstr.type = defaultConstrSym.type;
-
-        class DefaultConstructorPatcher extends TreeScanner {
-            @Override
-            public void visitApply(JCMethodInvocation tree) {
-                super.visitApply(tree);
-                tree.type = syms.voidType; //super constructor call has void type
-            }
-            @Override
-            public void visitIdent(JCIdent tree) {
-                if (tree.name == names._super) {
-                    //set super constructor symbol and type
-                    tree.sym = syms.objectType.tsym.members().lookup(names.init).sym;
-                    tree.type = tree.sym.type;
-                }
-            }
-        }
-
-        new DefaultConstructorPatcher().scan(defaultConstr);
-        return defaultConstr;
-    }
-
-    JCBlock makeLambdaBody(JCLambda tree) {
-        JCReturn defaultRet = null;
-        if (tree.canCompleteNormally &&
-                types.isSameType(tree.sym.type.getReturnType(), types.boxedClass(syms.voidType).type)) {
-            //there's no return statement and the lambda (possibly inferred)
-            //return type is java.lang.Void; sets the NEEDS_RETURN flag in
-            //order to tell code generation to emit a synthetic return statement
-            defaultRet = make.Return(make.Literal(TypeTags.BOT, null).setType(syms.botType));
-        }
-        JCBlock body = null;
-        if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION &&
-                tree.body.type != syms.voidType) {
-            body = make.Block(0, List.<JCStatement>of(make.Return((JCExpression)tree.body)));
-        } else {
-            switch (tree.body.getTag()) {
-                case JCTree.BLOCK: body = (JCBlock)tree.body; break;
-                default:
-                    JCStatement stat = make.Exec((JCExpression)tree.body);
-                    body = make.Block(0, List.<JCStatement>of(stat));
-            }
-        }
-        if (defaultRet != null) {
-            body.stats = body.stats.append(defaultRet);
-        }
-        return body;
-    }
-
-    @Override
-    public void visitIdent(JCIdent tree) {
-        if ((currentClass.sym.flags() & Flags.LAMBDA) != 0 &&
-                (tree.name == names._super ||
-                tree.name == names._this)) {
-            Type encl = tree.sym.owner.type;
-            result = make.Select(make.Type(types.erasure(encl)), tree.sym);
-        }
-        else if ((currentClass.sym.flags() & Flags.LAMBDA) != 0 &&
-                (tree.sym.kind == Kinds.VAR || tree.sym.kind == Kinds.MTH) &&
-                tree.sym.owner == syms.objectType.tsym) {
-            Type encl = currentClass.type.getEnclosingType();
-            while (encl != Type.noType && (encl.tsym.flags() & Flags.LAMBDA) != 0) {
-                encl = encl.getEnclosingType();
-            }
-            JCFieldAccess qualifiedThis =
-                    (JCFieldAccess)make.Select(make.Type(types.erasure(encl)),
-                                               names._this).setType(encl);
-            qualifiedThis.sym =  new VarSymbol(0, names._this, encl, encl.tsym);
-            result = make.Select(qualifiedThis, tree.sym);
-        }
-        else {
-            super.visitIdent(tree);
-        }
-    }
-
-    @Override
-    public void visitMethodDef(JCMethodDecl tree) {
-        if (tree.name == names.init &&
-                (currentClass.sym.flags() & Flags.LAMBDA) != 0) {
-            //skip synthetic constructor of lambda class
-            result = tree;
-            return;
-        }
-        super.visitMethodDef(tree);
-    }
-
-    @Override
-    public void visitReference(JCMemberReference tree) {
-        Type mhFactory = useProxy ? syms.proxyHelper : syms.methodHandleProxies;
-        Name mhInstName = useProxy ? names.makeProxy : names.asInterfaceInstance;
-        Symbol msym = rs.resolveInternalMethod(tree.pos(), attrEnv, mhFactory,
-                mhInstName, List.of(types.erasure(syms.classType),
-                syms.methodHandleType), List.<Type>nil());
-
-        JCFieldAccess qualifier = make.Select(make.QualIdent(mhFactory.tsym), mhInstName);
-        qualifier.sym = msym;
-        qualifier.type = msym.type;
-        
-        List<JCExpression> args = List.of(classLiteral(tree.type), tree);
-        JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, args, false);
-        proxyCall.type = types.erasure(qualifier.type);
-        result = proxyCall;
-    }
-    //where
-        JCExpression classLiteral(Type t) {
-            Type erasedClassType = types.erasure(syms.classType);
-            JCFieldAccess classLit =
-                    make.Select(make.Type(types.erasure(t)), names._class);
-            classLit.sym = new VarSymbol(
-                            Flags.STATIC | Flags.PUBLIC | Flags.FINAL, names._class, erasedClassType, t.tsym);
-            return classLit.setType(erasedClassType);
-        }
-
-    @Override
-    public void visitVarDef(final JCVariableDecl tree) {
-        if (tree.sym.owner.kind == Kinds.MTH &&
-                tree.init != null &&
-                tree.init.getTag() == JCTree.LAMBDA) {
-
-            //if this is a local variable initialized with a lambda expression
-            //we need to check whether the variable is referenced from the lambda
-
-            super.visitVarDef(tree);
-            JCClassDecl c = ((JCNewClass)tree.init).def;
-            final VarSymbol selfRef = new VarSymbol(0, names._this, c.type, c.sym);
-
-            //references to variable under initialization from lambda body
-            //are automatically turned into references to a synthetic field
-            //of the desugared lambda class
-            
-            class LambdaVarInitPatcher extends TreeScanner {
-                boolean needsCapture = true;
-                @Override
-                public void visitIdent(JCIdent that) {
-                    if (tree.sym == that.sym) {
-                        needsCapture = true;
-                        that.sym = selfRef;
-                        that.name = selfRef.name;
-                    }
-                }
-            }
-            LambdaVarInitPatcher lvis = new LambdaVarInitPatcher();
-            lvis.scan(tree.init);
-        } else {
-            super.visitVarDef(tree);
-        }
-    }
-}
--- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Thu Jul 14 11:10:07 2011 +0100
+++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Thu Jul 14 15:52:48 2011 +0100
@@ -266,7 +266,7 @@
 
     /** The lambda translator.
      */
-    protected Unlambda unlambda;
+    protected LambdaTranslator lambdaTranslator;
 
     /** The syntactic sugar desweetener.
      */
@@ -356,7 +356,6 @@
         gen = Gen.instance(context);
         flow = Flow.instance(context);
         transTypes = TransTypes.instance(context);
-        unlambda = Unlambda.instance(context);
         lower = Lower.instance(context);
         annotate = Annotate.instance(context);
         types = Types.instance(context);
@@ -366,6 +365,11 @@
 
         options = Options.instance(context);
 
+        //transitional: support two desugaring strategies
+        lambdaTranslator = options.isSet("lambdaToMethod") ?
+            LambdaToMethod.instance(context) :
+            LambdaToInnerClass.instance(context);
+
         verbose       = options.isSet(VERBOSE);
         sourceOutput  = options.isSet(PRINTSOURCE); // used to be -s
         stubOutput    = options.isSet("-stubs");
@@ -1339,7 +1343,7 @@
                 return;
             }
 
-            env.tree = unlambda.translateTopLevelClass(env, env.tree, localMake);
+            env.tree = lambdaTranslator.translateTopLevelClass(env, env.tree, localMake);
             compileStates.put(env, CompileState.UNLAMBDA);
 
             /**
--- a/src/share/classes/com/sun/tools/javac/util/Names.java	Thu Jul 14 11:10:07 2011 +0100
+++ b/src/share/classes/com/sun/tools/javac/util/Names.java	Thu Jul 14 15:52:48 2011 +0100
@@ -122,7 +122,6 @@
     public final Name invokeWithArguments;
     public final Name makeProxy;
     public final Name asInterfaceInstance;
-    public final Name newProxyInstance;
     public final Name lookup;
     public final Name findStatic;
     public final Name insertArguments;
@@ -253,7 +252,6 @@
         invokeWithArguments = fromString("invokeWithArguments");
         makeProxy = fromString("makeProxy");
         asInterfaceInstance = fromString("asInterfaceInstance");
-        newProxyInstance = fromString("newProxyInstance");
         lookup = fromString("lookup");
         fromMethodDescriptorString = fromString("fromMethodDescriptorString");
         findStatic = fromString("findStatic");