8008227: Mixing lambdas with anonymous classes leads to NPE thrown by compiler

Thu, 21 Feb 2013 15:19:29 +0000

author
mcimadamore
date
Thu, 21 Feb 2013 15:19:29 +0000
changeset 1595
d686d8a7eb78
parent 1594
267225edc1fe
child 1596
3a39d123d33a

8008227: Mixing lambdas with anonymous classes leads to NPE thrown by compiler
Summary: Disentangle cyclic dependency between static-ness of synthetic lambda method and static-ness of classes nested within lambdas
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java file | annotate | diff | comparison | revisions
test/tools/javac/lambda/LambdaConv27.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Feb 20 15:47:14 2013 -0800
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Feb 21 15:19:29 2013 +0000
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     1.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8   *
     1.9   * This code is free software; you can redistribute it and/or modify it
    1.10 @@ -125,7 +125,8 @@
    1.11              MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
    1.12                      List.<Type>nil(), syms.methodClass);
    1.13              deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym);
    1.14 -            deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), syms.serializedLambdaType, deserMethodSym);
    1.15 +            deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
    1.16 +                    syms.serializedLambdaType, deserMethodSym);
    1.17          }
    1.18  
    1.19          private void addMethod(JCTree decl) {
    1.20 @@ -738,7 +739,8 @@
    1.21                  List<Type> refPTypes = tree.sym.type.getParameterTypes();
    1.22                  int refSize = refPTypes.size();
    1.23                  int samSize = samPTypes.size();
    1.24 -                int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;   // Last parameter to copy from referenced method
    1.25 +                // Last parameter to copy from referenced method
    1.26 +                int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
    1.27  
    1.28                  List<Type> l = refPTypes;
    1.29                  // Use parameter types of the referenced method, excluding final var args
    1.30 @@ -763,7 +765,8 @@
    1.31                          null,
    1.32                          null);
    1.33                  bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
    1.34 -                bridgeDecl.type = localContext.bridgeSym.type = types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
    1.35 +                bridgeDecl.type = localContext.bridgeSym.type =
    1.36 +                        types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
    1.37  
    1.38                  //bridge method body generation - this can be either a method call or a
    1.39                  //new instance creation expression, depending on the member reference kind
    1.40 @@ -803,7 +806,8 @@
    1.41  
    1.42              //create the method call expression
    1.43              JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
    1.44 -                    convertArgs(tree.sym, args.toList(), tree.varargsElement)).setType(tree.sym.erasure(types).getReturnType());
    1.45 +                    convertArgs(tree.sym, args.toList(), tree.varargsElement)).
    1.46 +                    setType(tree.sym.erasure(types).getReturnType());
    1.47  
    1.48              apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
    1.49              setVarargsIfNeeded(apply, tree.varargsElement);
    1.50 @@ -817,7 +821,8 @@
    1.51          private JCExpression bridgeExpressionNew() {
    1.52              if (tree.kind == ReferenceKind.ARRAY_CTOR) {
    1.53                  //create the array creation expression
    1.54 -                JCNewArray newArr = make.NewArray(make.Type(types.elemtype(tree.getQualifierExpression().type)),
    1.55 +                JCNewArray newArr = make.NewArray(
    1.56 +                        make.Type(types.elemtype(tree.getQualifierExpression().type)),
    1.57                          List.of(make.Ident(params.first())),
    1.58                          null);
    1.59                  newArr.type = tree.getQualifierExpression().type;
    1.60 @@ -872,7 +877,8 @@
    1.61          Type mtype = types.erasure(tree.descriptorType);
    1.62          MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
    1.63          List<Object> staticArgs = List.<Object>of(
    1.64 -                new Pool.MethodHandle(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(tree.type.tsym), types),
    1.65 +                new Pool.MethodHandle(ClassFile.REF_invokeInterface,
    1.66 +                    types.findDescriptorSymbol(tree.type.tsym), types),
    1.67                  new Pool.MethodHandle(refKind, refSym, types),
    1.68                  new MethodType(mtype.getParameterTypes(),
    1.69                          mtype.getReturnType(),
    1.70 @@ -922,7 +928,8 @@
    1.71       * Generate an indy method call with given name, type and static bootstrap
    1.72       * arguments types
    1.73       */
    1.74 -    private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
    1.75 +    private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
    1.76 +            List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
    1.77          int prevPos = make.pos;
    1.78          try {
    1.79              make.at(pos);
    1.80 @@ -936,7 +943,9 @@
    1.81              DynamicMethodSymbol dynSym =
    1.82                      new DynamicMethodSymbol(names.lambda,
    1.83                                              syms.noSymbol,
    1.84 -                                            bsm.isStatic() ? ClassFile.REF_invokeStatic : ClassFile.REF_invokeVirtual,
    1.85 +                                            bsm.isStatic() ?
    1.86 +                                                ClassFile.REF_invokeStatic :
    1.87 +                                                ClassFile.REF_invokeVirtual,
    1.88                                              (MethodSymbol)bsm,
    1.89                                              indyType,
    1.90                                              staticArgs.toArray());
    1.91 @@ -1057,26 +1066,19 @@
    1.92          @Override
    1.93          public void visitClassDef(JCClassDecl tree) {
    1.94              List<Frame> prevStack = frameStack;
    1.95 -            Map<String, Integer> prevSerializableLambdaCount = serializableLambdaCounts;
    1.96 +            Map<String, Integer> prevSerializableLambdaCount =
    1.97 +                    serializableLambdaCounts;
    1.98              Map<ClassSymbol, Symbol> prevClinits = clinits;
    1.99              try {
   1.100                  serializableLambdaCounts = new HashMap<String, Integer>();
   1.101                  prevClinits = new HashMap<ClassSymbol, Symbol>();
   1.102                  if (directlyEnclosingLambda() != null) {
   1.103                      tree.sym.owner = owner();
   1.104 -                    LambdaTranslationContext lambdaContext = (LambdaTranslationContext) contextMap.get(directlyEnclosingLambda());
   1.105 -                    Type encl = lambdaContext.enclosingType();
   1.106 -                    if (encl.hasTag(NONE)) {
   1.107 -                        //if the translated lambda body occurs in a static context,
   1.108 -                        //any class declaration within it must be made static
   1.109 -                        //@@@TODO: What about nested classes within lambda?
   1.110 -                        tree.sym.flags_field |= STATIC;
   1.111 -                        ((ClassType) tree.sym.type).setEnclosingType(Type.noType);
   1.112 -                    } else {
   1.113 -                        //if the translated lambda body is in an instance context
   1.114 -                        //the enclosing type of any class declaration within it
   1.115 -                        //must be updated to point to the new enclosing type (if any)
   1.116 -                        ((ClassType) tree.sym.type).setEnclosingType(encl);
   1.117 +                    if (tree.sym.hasOuterInstance()) {
   1.118 +                        //if a class is defined within a lambda, the lambda must capture
   1.119 +                        //its enclosing instance (if any)
   1.120 +                        ((LambdaTranslationContext) context())
   1.121 +                                .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
   1.122                      }
   1.123                  }
   1.124                  frameStack = frameStack.prepend(new Frame(tree));
   1.125 @@ -1087,11 +1089,6 @@
   1.126                  serializableLambdaCounts = prevSerializableLambdaCount;
   1.127                  clinits = prevClinits;
   1.128              }
   1.129 -            if (!tree.sym.isStatic() && directlyEnclosingLambda() != null) {
   1.130 -                // Any (non-static) class defined within a lambda is an implicit 'this' reference
   1.131 -                // because its constructor will reference the enclosing class
   1.132 -                ((LambdaTranslationContext) context()).addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
   1.133 -            }
   1.134          }
   1.135  
   1.136          @Override
   1.137 @@ -1105,7 +1102,8 @@
   1.138                          if (localContext.tree.getTag() == LAMBDA) {
   1.139                              JCTree block = capturedDecl(localContext.depth, tree.sym);
   1.140                              if (block == null) break;
   1.141 -                            ((LambdaTranslationContext)localContext).addSymbol(tree.sym, CAPTURED_VAR);
   1.142 +                            ((LambdaTranslationContext)localContext)
   1.143 +                                    .addSymbol(tree.sym, CAPTURED_VAR);
   1.144                          }
   1.145                          localContext = localContext.prev;
   1.146                      }
   1.147 @@ -1118,7 +1116,8 @@
   1.148                              switch (block.getTag()) {
   1.149                                  case CLASSDEF:
   1.150                                      JCClassDecl cdecl = (JCClassDecl)block;
   1.151 -                                    ((LambdaTranslationContext)localContext).addSymbol(cdecl.sym, CAPTURED_THIS);
   1.152 +                                    ((LambdaTranslationContext)localContext)
   1.153 +                                            .addSymbol(cdecl.sym, CAPTURED_THIS);
   1.154                                      break;
   1.155                                  default:
   1.156                                      Assert.error("bad block kind");
   1.157 @@ -1165,7 +1164,8 @@
   1.158          @Override
   1.159          public void visitNewClass(JCNewClass tree) {
   1.160              if (lambdaNewClassFilter(context(), tree)) {
   1.161 -                ((LambdaTranslationContext) context()).addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
   1.162 +                ((LambdaTranslationContext) context())
   1.163 +                        .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
   1.164              }
   1.165              super.visitNewClass(tree);
   1.166          }
   1.167 @@ -1278,7 +1278,8 @@
   1.168                          return ((JCMethodDecl)frameStack2.head.tree).sym;
   1.169                      case LAMBDA:
   1.170                          if (!skipLambda)
   1.171 -                            return ((LambdaTranslationContext)contextMap.get(frameStack2.head.tree)).translatedSym;
   1.172 +                            return ((LambdaTranslationContext)contextMap
   1.173 +                                    .get(frameStack2.head.tree)).translatedSym;
   1.174                      default:
   1.175                          frameStack2 = frameStack2.tail;
   1.176                  }
   1.177 @@ -1555,7 +1556,8 @@
   1.178                          return sym;  // self represented
   1.179                      case TYPE_VAR:
   1.180                          // Just erase the type var
   1.181 -                        return new VarSymbol(sym.flags(), names.fromString(name), types.erasure(sym.type), sym.owner);
   1.182 +                        return new VarSymbol(sym.flags(), names.fromString(name),
   1.183 +                                types.erasure(sym.type), sym.owner);
   1.184                      default:
   1.185                          return makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
   1.186                  }
   1.187 @@ -1633,7 +1635,8 @@
   1.188  
   1.189                  // If instance access isn't needed, make it static
   1.190                  // Interface methods much be public default methods, otherwise make it private
   1.191 -                translatedSym.flags_field = SYNTHETIC | (needInstance? 0 : STATIC) | (inInterface? PUBLIC | DEFAULT : PRIVATE);
   1.192 +                translatedSym.flags_field = SYNTHETIC | (needInstance? 0 : STATIC) |
   1.193 +                        (inInterface? PUBLIC | DEFAULT : PRIVATE);
   1.194  
   1.195                  //compute synthetic params
   1.196                  ListBuffer<JCVariableDecl> params = ListBuffer.lb();
   1.197 @@ -1655,12 +1658,6 @@
   1.198                          TreeInfo.types(syntheticParams));
   1.199              }
   1.200  
   1.201 -            Type enclosingType() {
   1.202 -                return owner.isStatic() ?
   1.203 -                        Type.noType :
   1.204 -                        owner.enclClass().type;
   1.205 -            }
   1.206 -
   1.207              Type generatedLambdaSig() {
   1.208                  return types.erasure(tree.descriptorType);
   1.209              }
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/tools/javac/lambda/LambdaConv27.java	Thu Feb 21 15:19:29 2013 +0000
     2.3 @@ -0,0 +1,40 @@
     2.4 +/*
     2.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.
    2.11 + *
    2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.15 + * version 2 for more details (a copy is included in the LICENSE file that
    2.16 + * accompanied this code).
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License version
    2.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.21 + *
    2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    2.23 + * or visit www.oracle.com if you need additional information or have any
    2.24 + * questions.
    2.25 + */
    2.26 +
    2.27 +/*
    2.28 + * @test
    2.29 + * @bug 8008227
    2.30 + * @summary Mixing lambdas with anonymous classes leads to NPE thrown by compiler
    2.31 + * @run main LambdaConv27
    2.32 + */
    2.33 +public class LambdaConv27 {
    2.34 +
    2.35 +     public static void main(String[] args) {
    2.36 +         SAM s = ()-> { SAM s2 = ()->{ new Object() { }; }; s2.m(); };
    2.37 +         s.m();
    2.38 +     }
    2.39 +
    2.40 +     interface SAM {
    2.41 +         void m();
    2.42 +     }
    2.43 +}

mercurial