changeset 580:9f79be8946c6

Initial push for the 'defender methods' feature. The compiler recognizes and attributes the syntax described in the strawman proposal; defender methods are decorated with a special bytecode attribute called 'Defender'. It is also possible (using the -XDemitDefenderMethodAnnos flag) to have the compiler automatically generate a non-standard annotation called @DefenderMethod which contains information about the default implementation attached to the defender method declaration. Note: the current prototype doesn't commit to any of the implementation strategies described in the strawman; as such the code the compiler emits will not be executable (calling a defender method will result in an AbstractMethodError).
author mcimadamore
date Fri, 18 Jun 2010 13:02:01 +0100
parents 0bed895ea4d1
children 02b8de982628
files src/share/classes/com/sun/runtime/DefenderMethod.java src/share/classes/com/sun/tools/classfile/Attribute.java src/share/classes/com/sun/tools/classfile/ClassWriter.java src/share/classes/com/sun/tools/classfile/Defender_attribute.java src/share/classes/com/sun/tools/javac/code/Flags.java src/share/classes/com/sun/tools/javac/code/Source.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/Check.java src/share/classes/com/sun/tools/javac/comp/Flow.java src/share/classes/com/sun/tools/javac/comp/Lower.java src/share/classes/com/sun/tools/javac/comp/MemberEnter.java src/share/classes/com/sun/tools/javac/comp/Resolve.java src/share/classes/com/sun/tools/javac/jvm/ClassReader.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/Target.java src/share/classes/com/sun/tools/javac/parser/JavacParser.java src/share/classes/com/sun/tools/javac/resources/compiler.properties src/share/classes/com/sun/tools/javac/tree/JCTree.java src/share/classes/com/sun/tools/javac/util/Names.java src/share/classes/com/sun/tools/javap/AttributeWriter.java test/tools/javac/defender/Neg01.java test/tools/javac/defender/Neg01.out test/tools/javac/defender/Pos01.java test/tools/javac/defender/Pos02.java
diffstat 27 files changed, 534 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/runtime/DefenderMethod.java	Fri Jun 18 13:02:01 2010 +0100
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2008, 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.runtime;
+
+import java.lang.annotation.*;
+
+
+/**
+ *
+ * @author Maurizio Cimadamore
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface DefenderMethod {
+    String className();
+    String methodName();
+    String methodSignature();
+}
--- a/src/share/classes/com/sun/tools/classfile/Attribute.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/classfile/Attribute.java	Fri Jun 18 13:02:01 2010 +0100
@@ -43,6 +43,7 @@
     public static final String Code                     = "Code";
     public static final String ConstantValue            = "ConstantValue";
     public static final String CompilationID            = "CompilationID";
+    public static final String Defender               = "Defender";
     public static final String Deprecated               = "Deprecated";
     public static final String EnclosingMethod          = "EnclosingMethod";
     public static final String Exceptions               = "Exceptions";
@@ -165,6 +166,7 @@
         R visitCode(Code_attribute attr, P p);
         R visitCompilationID(CompilationID_attribute attr, P p);
         R visitConstantValue(ConstantValue_attribute attr, P p);
+        R visitDefender(Defender_attribute attr, P p);
         R visitDeprecated(Deprecated_attribute attr, P p);
         R visitEnclosingMethod(EnclosingMethod_attribute attr, P p);
         R visitExceptions(Exceptions_attribute attr, P p);
--- a/src/share/classes/com/sun/tools/classfile/ClassWriter.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/classfile/ClassWriter.java	Fri Jun 18 13:02:01 2010 +0100
@@ -376,6 +376,12 @@
             return null;
         }
 
+        public Void visitDefender(Defender_attribute attr, ClassOutputStream out) {
+            out.writeShort(attr.class_index);
+            out.writeShort(attr.method_index);
+            return null;
+        }
+
         public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) {
             return null;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/classfile/Defender_attribute.java	Fri Jun 18 13:02:01 2010 +0100
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010, 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.classfile;
+
+import java.io.IOException;
+
+/**
+ * Bytecode support for defender methods
+ *
+ *  <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 Defender_attribute extends Attribute {
+    Defender_attribute(ClassReader cr, int name_index, int length) throws IOException {
+        super(name_index, length);
+        class_index = cr.readUnsignedShort();
+        method_index = cr.readUnsignedShort();
+    }
+
+    public Defender_attribute(ConstantPool constant_pool, int class_index, int method_index)
+            throws ConstantPoolException {
+        this(constant_pool.getUTF8Index(Attribute.Defender), class_index, method_index);
+    }
+
+    public Defender_attribute(int name_index, int class_index, int method_index) {
+        super(name_index, 4);
+        this.class_index =  class_index;
+        this.method_index = method_index;
+    }
+
+    public <R, D> R accept(Visitor<R, D> visitor, D data) {
+        return visitor.visitDefender(this, data);
+    }
+
+    public String getClassName(ConstantPool constant_pool) throws ConstantPoolException {
+        return constant_pool.getClassInfo(class_index).getName();
+    }
+
+    public String getMethodName(ConstantPool constant_pool) throws ConstantPoolException {
+        if (method_index == 0)
+            return "";
+        return constant_pool.getNameAndTypeInfo(method_index).getName();
+    }
+
+    public final int class_index;
+    public final int method_index;
+}
--- a/src/share/classes/com/sun/tools/javac/code/Flags.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Flags.java	Fri Jun 18 13:02:01 2010 +0100
@@ -123,6 +123,7 @@
     public static final int ACC_SUPER    = 0x0020;
     public static final int ACC_BRIDGE   = 0x0040;
     public static final int ACC_VARARGS  = 0x0080;
+    public static final int ACC_DEFENDER = 0x0200;
 
     /*****************************************
      * Internal compiler flags (no bits in the lower 16).
@@ -246,6 +247,11 @@
      */
     public static final long OUTER_ACCESS = 1L<<41;
 
+    /**
+     * Flag that marks a defender method/interface
+     */
+    public static final long DEFENDER = 1L<<42;
+
     /** Modifier masks.
      */
     public static final int
@@ -259,7 +265,7 @@
         ConstructorFlags      = AccessFlags,
         InterfaceMethodFlags  = ABSTRACT | PUBLIC,
         MethodFlags           = AccessFlags | ABSTRACT | STATIC | NATIVE |
-                                SYNCHRONIZED | FINAL | STRICTFP;
+                                SYNCHRONIZED | FINAL | STRICTFP | ACC_DEFENDER;
     public static final long
         LocalVarFlags         = FINAL | PARAMETER;
 
@@ -333,7 +339,8 @@
         PARAMETER("parameter"),
         VARARGS("varargs"),
         PACKAGE("package"),
-        THROW("throw");
+        THROW("throw"),
+        DEFENDER("defender");
 
         String name;
 
--- a/src/share/classes/com/sun/tools/javac/code/Source.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Source.java	Fri Jun 18 13:02:01 2010 +0100
@@ -128,6 +128,9 @@
     public boolean allowMulticatch() {
         return compareTo(JDK1_7) >= 0;
     }
+    public boolean allowDefenderMethods() {
+        return compareTo(JDK1_7) >= 0;
+    }
     public boolean allowEnums() {
         return compareTo(JDK1_5) >= 0;
     }
--- a/src/share/classes/com/sun/tools/javac/code/Symbol.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Jun 18 13:02:01 2010 +0100
@@ -1034,6 +1034,11 @@
         /** The names of the parameters */
         public List<Name> savedParameterNames;
 
+        /** Symbol corresponding to the method's default implementation
+         * (used for defender methods);
+         */
+        public Symbol defaultImpl = null;
+
         /** For an attribute field accessor, its default value if any.
          *  The value is null if none appeared in the method
          *  declaration.
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java	Fri Jun 18 13:02:01 2010 +0100
@@ -154,6 +154,7 @@
     public final Type proprietaryType;
     public final Type systemType;
     public final Type proxyHelper;
+    public final Type defenderMethodType;
 
     /** The symbol representing the length field of an array.
      */
@@ -474,6 +475,7 @@
         inheritedType = enterClass("java.lang.annotation.Inherited");
         systemType = enterClass("java.lang.System");
         proxyHelper = enterClass("com.sun.runtime.ProxyHelper");
+        defenderMethodType = enterClass("com.sun.runtime.DefenderMethod");
 
         synthesizeEmptyInterfaceIfMissing(cloneableType);
         synthesizeEmptyInterfaceIfMissing(serializableType);
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Jun 18 13:02:01 2010 +0100
@@ -279,6 +279,19 @@
         return rs.resolveSelf(pos, env, env.enclClass.sym, names._this);
     }
 
+    /** The `this' symbol corresponding to an implemented defender interface.
+     *  @param env    The current environment.
+     */
+    Symbol defenderThisSym(DiagnosticPosition pos, Env<AttrContext> env, Type type) {
+        if (types.asSuper(env.enclClass.type, type.tsym) == null ||
+                (type.tsym.flags() & DEFENDER) == 0) {
+            throw new AssertionError();
+        }
+        Symbol thisSym = thisSym(pos, env).clone(env.info.scope.owner);
+        thisSym.type = type;
+        return thisSym;
+    }
+
     /** Attribute a parsed identifier.
      * @param tree Parsed identifier name
      * @param topLevel The toplevel to use
@@ -632,6 +645,7 @@
 
     public void visitMethodDef(JCMethodDecl tree) {
         MethodSymbol m = tree.sym;
+        boolean isDefender = (m.flags() & DEFENDER) != 0;
 
         Lint lint = env.info.lint.augment(m.attributes_field, m.flags());
         Lint prevLint = chk.setLint(lint);
@@ -650,6 +664,13 @@
 
             localEnv.info.lint = lint;
 
+            if (isDefender) {
+                //when attributing defender method body we need a synthetic 'this' variable
+                //whose type is the type of the enclosing interface
+                VarSymbol _this = new VarSymbol(0, names._this, m.owner.type, m.owner);
+                localEnv.info.scope.enter(_this);
+            }
+
             // Enter all type parameters into the local method scope.
             for (List<JCTypeParameter> l = tree.typarams; l.nonEmpty(); l = l.tail)
                 localEnv.info.scope.enterIfAbsent(l.head.type.tsym);
@@ -701,7 +722,7 @@
                         log.error(tree.pos(),
                                   "default.allowed.in.intf.annotation.member");
                 }
-            } else if ((owner.flags() & INTERFACE) != 0) {
+            } else if ((owner.flags() & INTERFACE) != 0 && !isDefender) {
                 log.error(tree.body.pos(), "intf.meth.cant.have.body");
             } else if ((tree.mods.flags & ABSTRACT) != 0) {
                 log.error(tree.pos(), "abstract.meth.cant.have.body");
@@ -735,6 +756,18 @@
 
                 // Attribute method body.
                 attribStat(tree.body, localEnv);
+
+                if (isDefender) {
+                    //check that default expression is of right type
+                    if (tree.body.stats.head.getTag() != JCTree.EXEC ||
+                            ((JCExpressionStatement)tree.body.stats.head).expr.getTag() != JCTree.APPLY) {
+                        log.error(tree.body.stats.head, "bad.defender.method.body");
+                    } else {
+                        JCTree defaultImpl = ((JCExpressionStatement)tree.body.stats.head).expr;
+                        chk.checkType(defaultImpl, defaultImpl.type, m.type.getReturnType());
+                        m.defaultImpl = TreeInfo.symbol(((JCMethodInvocation)defaultImpl).meth);
+                    }
+                }
             }
             localEnv.info.scope.leave();
             result = tree.type = m.type;
@@ -2342,7 +2375,10 @@
                     return rs.resolveQualifiedMethod(
                         pos, env, site, name, pt.getParameterTypes(), pt.getTypeArguments());
                 } else if (name == names._this || name == names._super) {
-                    return rs.resolveSelf(pos, env, site.tsym, name);
+                    return ((site.tsym.flags() & DEFENDER) != 0 &&
+                            types.asSuper(env.enclClass.type, site.tsym) != null) ?
+                                defenderThisSym(pos, env, site) :
+                                rs.resolveSelf(pos, env, site.tsym, name);
                 } else if (name == names._class) {
                     // In this case, we have already made sure in
                     // visitSelect that qualifier expression is a type.
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Jun 18 13:02:01 2010 +0100
@@ -1753,7 +1753,7 @@
                      undef == null && e != null;
                      e = e.sibling) {
                     if (e.sym.kind == MTH &&
-                        (e.sym.flags() & (ABSTRACT|IPROXY)) == ABSTRACT) {
+                        (e.sym.flags() & (ABSTRACT|IPROXY|DEFENDER)) == ABSTRACT) {
                         MethodSymbol absmeth = (MethodSymbol)e.sym;
                         MethodSymbol implmeth = absmeth.implementation(impl, types, true);
                         if (implmeth == null || implmeth == absmeth)
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Jun 18 13:02:01 2010 +0100
@@ -693,7 +693,8 @@
     }
 
     public void visitMethodDef(JCMethodDecl tree) {
-        if (tree.body == null) return;
+        if (tree.body == null ||
+                (tree.sym.flags() & DEFENDER) != 0) return;
 
         List<Type> caughtPrev = caught;
         List<Type> mthrown = tree.sym.type.getThrownTypes();
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Jun 18 13:02:01 2010 +0100
@@ -39,6 +39,7 @@
 import com.sun.tools.javac.code.Type.*;
 
 import com.sun.tools.javac.jvm.Target;
+import com.sun.tools.javac.main.OptionName;
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
@@ -82,6 +83,7 @@
     private final Name classDollar;
     private Types types;
     private boolean debugLower;
+    private boolean emitDefenderMethodAnnos;
 
     protected Lower(Context context) {
         context.put(lowerKey, this);
@@ -106,6 +108,7 @@
         types = Types.instance(context);
         Options options = Options.instance(context);
         debugLower = options.get("debuglower") != null;
+        emitDefenderMethodAnnos = options.get("emitDefenderMethodAnnos") != null;
     }
 
     /** The currently enclosing class.
@@ -1396,6 +1399,9 @@
         if (currentClass == c && lambdaStack.isEmpty()) {
             // in this case, `this' works fine
             return make.at(pos).This(c.erasure(types));
+        } else if ((c.flags() & DEFENDER) != 0 &&
+                types.asSuper(currentClass.type, c) != null) {
+           return make.at(pos).This(c.erasure(types));
         } else {
             // need to go via this$n
             return makeOuterThis(pos, c);
@@ -2361,6 +2367,26 @@
             }
         }
 
+        if ((tree.sym.flags() & DEFENDER) != 0 &&
+                emitDefenderMethodAnnos) {
+            //add synthetic @DefenderMethod annotation
+            ListBuffer<Pair<MethodSymbol, Attribute>> values = ListBuffer.lb();
+
+            MethodSymbol _className = lookupMethod(tree.pos(), names._className, syms.defenderMethodType, List.<Type>nil());
+            String _classNameVal = tree.sym.defaultImpl.enclClass().flatName().toString();
+            values.append(new Pair<MethodSymbol, Attribute>(_className, new Attribute.Constant(syms.stringType, _classNameVal)));
+
+            MethodSymbol _methodName = lookupMethod(tree.pos(), names._methodName, syms.defenderMethodType, List.<Type>nil());
+            String _methodNameVal = tree.sym.defaultImpl.name.toString();
+            values.append(new Pair<MethodSymbol, Attribute>(_methodName, new Attribute.Constant(syms.stringType, _methodNameVal)));
+
+            MethodSymbol _methodSignature = lookupMethod(tree.pos(), names._methodSignature, syms.defenderMethodType, List.<Type>nil());
+            String _methodSignatureVal = writer.typeSig(types.erasure(tree.sym.defaultImpl.type)).toString();
+            values.append(new Pair<MethodSymbol, Attribute>(_methodSignature, new Attribute.Constant(syms.stringType, _methodSignatureVal)));
+
+            tree.sym.attributes_field = tree.sym.attributes_field.prepend(new Attribute.Compound(syms.defenderMethodType, values.toList()));
+        }
+
         JCMethodDecl prevMethodDef = currentMethodDef;
         MethodSymbol prevMethodSym = currentMethodSym;
         try {
@@ -3633,10 +3659,15 @@
 
     public void visitSelect(JCFieldAccess tree) {
         // need to special case-access of the form C.super.x
-        // these will always need an access method.
+        // these will always need an access method, unless C
+        // is a defender interface subclassed by the current class.
+        boolean isDefenderAccess =
+                (tree.selected.type.tsym.flags() & DEFENDER) != 0 &&
+                types.asSuper(currentClass.type, tree.selected.type.tsym) != null;
         boolean qualifiedSuperAccess =
             tree.selected.getTag() == JCTree.SELECT &&
-            TreeInfo.name(tree.selected) == names._super;
+            TreeInfo.name(tree.selected) == names._super &&
+            !isDefenderAccess;
         tree.selected = translate(tree.selected);
         if (tree.name == names._class)
             result = classOf(tree.selected);
--- a/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Fri Jun 18 13:02:01 2010 +0100
@@ -569,6 +569,12 @@
         MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner);
         m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree);
         tree.sym = m;
+
+        //if this is a defender method, add the DEFENDER flag to the enclosing interface
+        if ((tree.mods.flags & DEFENDER) != 0) {
+            m.owner.flags_field |= DEFENDER;
+        }
+
         Env<AttrContext> localEnv = methodEnv(tree, env);
 
         // Compute the method type
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Jun 18 13:02:01 2010 +0100
@@ -664,8 +664,10 @@
                      (m1.owner.flags_field & INTERFACE) != 0) &&
                     m2.overrides(m1, m2Owner, types, false))
                     return m2;
-                boolean m1Abstract = (m1.flags() & ABSTRACT) != 0;
-                boolean m2Abstract = (m2.flags() & ABSTRACT) != 0;
+                boolean m1Abstract = (m1.flags() & ABSTRACT) != 0 &&
+                        (m1.flags() & DEFENDER) == 0;
+                boolean m2Abstract = (m2.flags() & ABSTRACT) != 0 &&
+                        (m2.flags() & DEFENDER) == 0;
                 if (m1Abstract && !m2Abstract) return m2;
                 if (m2Abstract && !m1Abstract) return m1;
                 // both abstract or both concrete
@@ -792,23 +794,26 @@
             if (name == names.init)
                 break;
             //- System.out.println(" - " + bestSoFar);
-            if (abstractok) {
-                Symbol concrete = methodNotFound;
-                if ((bestSoFar.flags() & ABSTRACT) == 0)
-                    concrete = bestSoFar;
-                for (List<Type> l = types.interfaces(c.type);
-                     l.nonEmpty();
-                     l = l.tail) {
-                    bestSoFar = findMethod(env, site, name, argtypes,
-                                           typeargtypes,
-                                           l.head, abstractok, bestSoFar,
-                                           allowBoxing, useVarargs, operator);
-                }
-                if (concrete != bestSoFar &&
-                    concrete.kind < ERR  && bestSoFar.kind < ERR &&
-                    types.isSubSignature(concrete.type, bestSoFar.type))
-                    bestSoFar = concrete;
+            Symbol concrete = methodNotFound;
+            if ((bestSoFar.flags() & ABSTRACT) == 0)
+                concrete = bestSoFar;
+            for (List<Type> l = types.interfaces(c.type);
+                 l.nonEmpty();
+                 l = l.tail) {
+                boolean abstractok2 = abstractok || (l.head.tsym.flags() & DEFENDER) != 0;
+                Symbol s2 = findMethod(env, site, name, argtypes,
+                                       typeargtypes,
+                                       l.head, abstractok2, bestSoFar,
+                                       allowBoxing, useVarargs, operator);
+                bestSoFar = s2.kind <= AMBIGUOUS && abstractok2 ?
+                    s2 :
+                    bestSoFar;
             }
+            if (concrete != bestSoFar &&
+                concrete.kind < ERR  && bestSoFar.kind < ERR &&
+                types.isSubSignature(concrete.type, bestSoFar.type))
+                bestSoFar = concrete;
+            
         }
         return bestSoFar;
     }
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Jun 18 13:02:01 2010 +0100
@@ -1850,6 +1850,9 @@
      */
     MethodSymbol readMethod() {
         long flags = adjustMethodFlags(nextChar());
+        if ((flags & DEFENDER) != 0) {
+            currentOwner.flags_field |= DEFENDER;
+        }
         Name name = readName(nextChar());
         Type type = readType(nextChar());
         if (name == names.init && currentOwner.hasOuterInstance()) {
@@ -2139,9 +2142,13 @@
             flags &= ~ACC_VARARGS;
             flags |= VARARGS;
         }
+        if ((flags & ACC_DEFENDER) != 0) {
+            flags &= ~ACC_DEFENDER;
+            flags |= DEFENDER;
+        }
         return flags;
     }
-    long adjustClassFlags(long flags) {
+    long adjustClassFlags(long flags) {        
         return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded
     }
 
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Fri Jun 18 13:02:01 2010 +0100
@@ -626,6 +626,23 @@
         return 1;
     }
 
+    /** Write the EnclosingMethod attribute if needed.
+     *  Returns the number of attributes written (0 or 1).
+     */
+    int writeDefenderAttribute(MethodSymbol m) {
+        if (!target.hasDefenderAttribute() ||
+                (m.flags() & DEFENDER) == 0 ||
+                m.defaultImpl == null)
+            return 0;
+
+        int alenIdx = writeAttr(names.Defender);
+        ClassSymbol enclClass = m.enclClass();
+        databuf.appendChar(pool.put(enclClass));
+        databuf.appendChar(pool.put(nameType(m.defaultImpl)));
+        endAttr(alenIdx);
+        return 1;
+    }
+
     /** Write flag attributes; return number of attributes written.
      */
     int writeFlagAttrs(long flags) {
@@ -1132,6 +1149,7 @@
         }
         acount += writeMemberAttrs(m);
         acount += writeParameterAttrs(m);
+        acount += writeDefenderAttribute(m);
         endAttrs(acountIdx, acount);
     }
 
@@ -1636,7 +1654,7 @@
         List<Type> interfaces = types.interfaces(c.type);
         List<Type> typarams = c.type.getTypeArguments();
 
-        int flags = adjustFlags(c.flags());
+        int flags = adjustFlags(c.flags() & ~DEFENDER);
         if ((flags & PROTECTED) != 0) flags |= PUBLIC;
         flags = flags & ClassFlags & ~STRICTFP;
         if ((flags & INTERFACE) == 0) flags |= ACC_SUPER;
@@ -1750,6 +1768,8 @@
             result |= ACC_BRIDGE;
         if ((flags & VARARGS) != 0  && target.useVarargsFlag())
             result |= ACC_VARARGS;
+        if ((flags & DEFENDER) != 0  && target.useDefenderFlag())
+            result |= ACC_DEFENDER;
         return result;
     }
 
--- a/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Jun 18 13:02:01 2010 +0100
@@ -903,7 +903,8 @@
                 nerrs++;
             }
 
-            else if (tree.body != null) {
+            else if (tree.body != null &&
+                    (tree.sym.flags() & DEFENDER) == 0) {
                 // Create a new code structure and initialize it.
                 int startpcCrt = initCode(tree, env, fatcode);
 
--- a/src/share/classes/com/sun/tools/javac/jvm/Target.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/Target.java	Fri Jun 18 13:02:01 2010 +0100
@@ -239,6 +239,9 @@
     public boolean useBridgeFlag() {
         return compareTo(JDK1_5) >= 0;
     }
+    public boolean useDefenderFlag() {
+        return compareTo(JDK1_7) >= 0;
+    }
 
     /** Return the character to be used in constructing synthetic
      *  identifiers, where not specified by the JLS.
@@ -306,4 +309,11 @@
     public boolean hasEnclosingMethodAttribute() {
         return compareTo(JDK1_5) >= 0 || this == JSR14;
     }
+
+    /** In JDK 7 we introduced the 'Defender' attribute for supporting
+     *  the defender methods language feature
+     */
+    public boolean hasDefenderAttribute() {
+        return compareTo(JDK1_7) >= 0;
+    }
 }
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Jun 18 13:02:01 2010 +0100
@@ -134,6 +134,7 @@
         this.allowAnnotations = source.allowAnnotations();
         this.allowDiamond = source.allowDiamond();
         this.allowMulticatch = source.allowMulticatch();
+        this.allowDefenderMethods = source.allowDefenderMethods();
         this.allowTypeAnnotations = source.allowTypeAnnotations();
         this.allowThrowTypeParameters = source.allowThrowTypeParameters();
         this.allowLambda = source.allowLambda();
@@ -163,6 +164,10 @@
      */
     boolean allowMulticatch;
 
+    /** Switch: Should defender methods declaration be accepted?
+     */
+    boolean allowDefenderMethods;
+
     /** Switch: Should varargs be recognized?
      */
     boolean allowVarargs;
@@ -2851,13 +2856,14 @@
      *  InterfaceBodyDeclaration =
      *      ";"
      *    | ModifiersOpt Type Ident
-     *      ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" )
+     *      ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest | DefenderMethodDeclaratorRest ";" )
      */
     List<JCTree> classOrInterfaceBodyDeclaration(Name className, boolean isInterface) {
         if (S.token() == SEMI) {
             S.nextToken();
             return List.<JCTree>of(F.at(Position.NOPOS).Block(0, List.<JCStatement>nil()));
         } else {
+            boolean isExtension = false;
             String dc = S.docComment();
             int pos = S.pos();
             JCModifiers mods = modifiersOpt();
@@ -2875,6 +2881,12 @@
                 List<JCAnnotation> annosAfterParams = annotationsOpt(AnnotationKind.DEFAULT_ANNO);
 
                 Name name = S.name();
+                if (isInterface && name.equals(names._extension)) {
+                    checkDefenderMethods();
+                    accept(IDENTIFIER);
+                    mods.flags |= Flags.DEFENDER;
+                    isExtension = true;
+                }
                 pos = S.pos();
                 JCExpression type;
                 boolean isVoid = S.token() == VOID;
@@ -2897,14 +2909,14 @@
                         log.error(pos, "invalid.meth.decl.ret.type.req");
                     return List.of(methodDeclaratorRest(
                         pos, mods, null, names.init, typarams,
-                        isInterface, true, dc));
+                        isInterface, true, isExtension, dc));
                 } else {
                     pos = S.pos();
                     name = ident();
                     if (S.token() == LPAREN) {
                         return List.of(methodDeclaratorRest(
                             pos, mods, type, name, typarams,
-                            isInterface, isVoid, dc));
+                            isInterface, isVoid, isExtension, dc));
                     } else if (!isVoid && typarams.isEmpty()) {
                         List<JCTree> defs =
                             variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
@@ -2935,6 +2947,8 @@
      *      FormalParameters [Annotations] [THROWS TypeList] ";"
      *  ConstructorDeclaratorRest =
      *      "(" FormalParameterListOpt ")" [Annotations] [THROWS TypeList] MethodBody
+     *  DefenderMethodDeclaratorRest =
+     *      "(" FormalParameterListOpt ")" [Annotations] [THROWS TypeList] DEFAULT IDENT { '.' [TYPEARGS] IDENT }
      */
     JCTree methodDeclaratorRest(int pos,
                               JCModifiers mods,
@@ -2942,6 +2956,7 @@
                               Name name,
                               List<JCTypeParameter> typarams,
                               boolean isInterface, boolean isVoid,
+                              boolean isDefender,
                               String dc) {
         List<JCVariableDecl> params = formalParameters();
 
@@ -2967,7 +2982,36 @@
         }
         JCBlock body = null;
         JCExpression defaultValue;
-        if (S.token() == LBRACE) {
+        if (isDefender) {
+            //a defender method declaration is turned into an ordinary method
+            //declaration where the method body is a standard method call to
+            //the extended method.
+            //
+            // e.g.
+            // extension T reduce(T arg) default Collections.<T>reduce;
+            //
+            // --> T reduce(T arg) { Collections.<T>reduce(this, arg); }
+            int prevMode = mode;
+            mode = EXPR;
+            accept(DEFAULT);
+            List<JCExpression> defenderMethodParams = List.<JCExpression>of(toP(F.at(pos).Ident(names._this)));
+            for (JCVariableDecl param : params) {
+                defenderMethodParams =
+                        defenderMethodParams.append(toP(F.at(pos).Ident(param.name)));
+            }
+            List<JCExpression> args = typeArgumentsOpt();
+            JCExpression meth = toP(F.at(pos).Ident(ident()));
+            while (args == null && S.token() == DOT) {
+                accept(DOT);
+                args = typeArgumentsOpt(EXPR);
+                meth = toP(F.at(pos).Select(meth, ident()));
+            }
+            JCMethodInvocation defaultImpl = toP(F.at(pos).Apply(args, meth, defenderMethodParams));
+            body = toP(F.at(pos).Block(0, List.<JCStatement>of(toP(F.at(pos).Exec(defaultImpl)))));
+            defaultValue = null;
+            mode = prevMode;
+        }
+        else if (S.token() == LBRACE) {
             body = block();
             defaultValue = null;
         } else {
@@ -3371,4 +3415,10 @@
             allowThrowTypeParameters = true;
         }
     }
+    void checkDefenderMethods() {
+        if (!allowDefenderMethods) {
+            log.error(S.pos(), "defender.methods.not.supported.in.source", source.name);
+            allowDefenderMethods = true;
+            }
+    }
 }
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Jun 18 13:02:01 2010 +0100
@@ -129,6 +129,8 @@
     call to super not allowed in enum constructor
 compiler.err.no.superclass=\
     {0} has no superclass
+compiler.err.bad.defender.method.body=\
+    body of defender method must be a method call
 
 compiler.err.concrete.inheritance.conflict=\
     methods {0} from {1} and {2} from {3} are inherited with the same signature
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Jun 18 13:02:01 2010 +0100
@@ -684,6 +684,10 @@
         public JCTree getDefaultValue() { // for annotation types
             return defaultValue;
         }
+        public boolean isExtended() {
+            //return mods.getFlags().contains(Modifier.DEFENDER);
+            return false;
+        }
         @Override
         public <R,D> R accept(TreeVisitor<R,D> v, D d) {
             return v.visitMethod(this, d);
--- a/src/share/classes/com/sun/tools/javac/util/Names.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/util/Names.java	Fri Jun 18 13:02:01 2010 +0100
@@ -91,6 +91,7 @@
     public final Name InnerClasses;
     public final Name Synthetic;
     public final Name Bridge;
+    public final Name Defender;
     public final Name Deprecated;
     public final Name Enum;
     public final Name _name;
@@ -157,6 +158,10 @@
     public final Name getDeclaringClass;
     public final Name ex;
     public final Name finalize;
+    public final Name _extension;
+    public final Name _className;
+    public final Name _methodName;
+    public final Name _methodSignature;
 
     public final Name.Table table;
 
@@ -210,6 +215,7 @@
         InnerClasses = fromString("InnerClasses");
         Synthetic = fromString("Synthetic");
         Bridge = fromString("Bridge");
+        Defender = fromString("Defender");
         Deprecated = fromString("Deprecated");
         Enum = fromString("Enum");
         _name = fromString("name");
@@ -281,6 +287,10 @@
         getDeclaringClass = fromString("getDeclaringClass");
         ex = fromString("ex");
         finalize = fromString("finalize");
+        _extension = fromString("extension");
+        _className = fromString("className");
+        _methodName = fromString("methodName");
+        _methodSignature = fromString("methodSignature");
     }
 
     protected Name.Table createTable(Options options) {
--- a/src/share/classes/com/sun/tools/javap/AttributeWriter.java	Thu Jun 17 13:24:27 2010 +0100
+++ b/src/share/classes/com/sun/tools/javap/AttributeWriter.java	Fri Jun 18 13:02:01 2010 +0100
@@ -38,6 +38,7 @@
 import com.sun.tools.classfile.ConstantPoolException;
 import com.sun.tools.classfile.ConstantValue_attribute;
 import com.sun.tools.classfile.DefaultAttribute;
+import com.sun.tools.classfile.Defender_attribute;
 import com.sun.tools.classfile.Deprecated_attribute;
 import com.sun.tools.classfile.EnclosingMethod_attribute;
 import com.sun.tools.classfile.Exceptions_attribute;
@@ -211,6 +212,16 @@
         println();
         return null;
     }
+    
+    public Void visitDefender(Defender_attribute attr, Void ignore) {
+        print("Defender: #" + attr.method_index);
+        tab();
+        print("// " + getJavaClassName(attr));
+        if (attr.method_index != 0)
+            print("." + getMethodName(attr));
+        println();
+        return null;
+    }
 
     public Void visitDeprecated(Deprecated_attribute attr, Void ignore) {
         println("Deprecated: true");
@@ -243,6 +254,22 @@
         }
     }
 
+    private String getJavaClassName(Defender_attribute a) {
+        try {
+            return getJavaName(a.getClassName(constant_pool));
+        } catch (ConstantPoolException e) {
+            return report(e);
+        }
+    }
+
+    private String getMethodName(Defender_attribute a) {
+        try {
+            return a.getMethodName(constant_pool);
+        } catch (ConstantPoolException e) {
+            return report(e);
+        }
+    }
+
     public Void visitExceptions(Exceptions_attribute attr, Void ignore) {
         println("Exceptions:");
         indent(+1);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Neg01.java	Fri Jun 18 13:02:01 2010 +0100
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary negative test for ambiguous defender methods
+ * @author  Maurizio Cimadamore
+ * @compile/fail/ref=Neg01.out -XDrawDiagnostics Neg01.java
+ */
+
+class Neg01 {
+    interface IA { extension int m() default Neg01.m1; }
+    interface IB { extension int m() default Neg01.m2; }
+
+    static class A implements IA {}
+    static class B implements IB {}
+
+    static class AB implements IA, IB {}
+
+    static int m1(IA a) { return 0; }
+    static int m2(IB b) { return 0; }
+
+    static void test() {
+        new AB().m(); //ambiguous
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Neg01.out	Fri Jun 18 13:02:01 2010 +0100
@@ -0,0 +1,2 @@
+Neg01.java:44:17: compiler.err.ref.ambiguous: m, kindname.method, m(), Neg01.IB, kindname.method, m(), Neg01.IA
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Pos01.java	Fri Jun 18 13:02:01 2010 +0100
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary basic test for defender methods
+ * @author  Maurizio Cimadamore
+ * @compile Pos01.java
+ */
+
+import java.util.*;
+
+class Pos01 {
+
+    interface Mapper<T> {
+        T map(T in);
+    }
+
+    interface ExtendedList<T> extends List<T> {
+        extension List<T> map(Mapper<T> r)
+            default Pos01.<T>listMapper;
+    }
+
+    static class MyList<E> extends ArrayList<E> implements ExtendedList<E> {}
+
+    public static void main(String[] args) {
+       MyList<Integer> l = new MyList<Integer>();
+       l.add(1); l.add(2); l.add(3);
+       l.map(#(Integer x)(x * x));
+    }
+
+    static <T> List<T> listMapper(List<T> l, Mapper<T> mapper) {
+        MyList<T> new_list = new MyList<T>();
+        for (T el : l) {
+            new_list.add(mapper.map(el));
+        }
+        return new_list;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Pos02.java	Fri Jun 18 13:02:01 2010 +0100
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary test for explicit resolution of ambiguous defender methods
+ * @author  Maurizio Cimadamore
+ * @compile Pos02.java
+ */
+
+class Pos02 {
+    interface IA { extension int m() default Pos02.m1; }
+    interface IB { extension int m() default Pos02.m2; }
+
+    static class A implements IA {}
+    static class B implements IB {}
+
+    static class AB implements IA, IB {
+        void test() {
+            IA.this.m();
+            IA.super.m();
+        }
+    }
+
+    static int m1(IA a) { return 0; }
+    static int m2(IB b) { return 0; }
+}