OpenJDK / lambda / lambda / langtools
changeset 1464:0e71dd95f7ef
Lambda compilation: move translatedSym completion into translation context. Misc clean-up. Documentation
author | robert.field@oracle.com |
---|---|
date | Wed, 26 Sep 2012 22:29:05 -0700 |
parents | e23bb5d64f58 |
children | a5521ef3db10 |
files | src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java |
diffstat | 1 files changed, 80 insertions(+), 58 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Tue Sep 25 14:45:58 2012 +0100 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Wed Sep 26 22:29:05 2012 -0700 @@ -80,6 +80,12 @@ // </editor-fold> // <editor-fold defaultstate="collapsed" desc="visitor methods"> + /** + * Visit a class. + * Maintain the translatedMethodList across nested classes. + * Append the translatedMethodList to the class after it is translated. + * @param tree + */ @Override public void visitClassDef(JCClassDecl tree) { if (tree.sym.owner.kind == PCK) { @@ -101,75 +107,44 @@ } } + /** + * Translate a lambda into a method to be inserted into the class. + * Then replace the lambda site with an invokedynamic call of to lambda + * meta-factory, which will use the lambda method. + * @param tree + */ @Override public void visitLambda(JCLambda tree) { - //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). + LambdaToMethodTranslationContext localContext = (LambdaToMethodTranslationContext)context; + MethodSymbol sym = (MethodSymbol)localContext.translatedSym; + MethodType lambdaType = (MethodType) sym.type; + boolean isStatic = sym.isStatic(); - LambdaToMethodTranslationContext localContext = (LambdaToMethodTranslationContext)context; - boolean inInterface = localContext.translatedSym.owner.isInterface(); - boolean isBound = !localContext.getSymbolMap(CAPTURED_THIS).isEmpty() || inInterface; - - // @@@ flag fix-up -- Robert, clean this up - if (isBound) { - // Need access to implicit or explicit 'this' - localContext.translatedSym.flags_field &= ~STATIC; - } - if (inInterface) { - // Interface methods much public default methods - localContext.translatedSym.flags_field |= PUBLIC | DEFENDER; - } else { - // All other introduced methods can be private - localContext.translatedSym.flags_field |= PRIVATE; - } - - //compute synthetic params - ListBuffer<JCVariableDecl> syntheticParams = ListBuffer.lb(); - - //add cap$n and $n if needed - for (Symbol thisSym : localContext.getSymbolMap(CAPTURED_VAR, PARAM).values()) { - syntheticParams.append(make.VarDef((VarSymbol)thisSym, null)); - } - - //prepend synthetic args to translated lambda method signature - MethodType lambdaType = (MethodType)localContext.generatedLambdaSig(); - localContext.translatedSym.type = lambdaType = (MethodType)types.createMethodTypeWithParameters(lambdaType, TreeInfo.types(syntheticParams.toList())); - - //create method declaration hoisting the lambda body - - long mods = SYNTHETIC; - if (!isBound) { - mods |= STATIC; - } + //create the method declaration hoisting the lambda body + long mods = isStatic? (STATIC | SYNTHETIC) : (SYNTHETIC); JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(mods), - localContext.translatedSym.name, + sym.name, make.QualIdent(lambdaType.getReturnType().tsym), List.<JCTypeParameter>nil(), - syntheticParams.toList(), + localContext.syntheticParams, lambdaType.getThrownTypes() == null ? List.<JCExpression>nil() : make.Types(lambdaType.getThrownTypes()), null, null); - lambdaDecl.sym = (MethodSymbol)localContext.translatedSym; + lambdaDecl.sym = sym; lambdaDecl.type = lambdaType; //translate lambda body + //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). lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl)); + //Add the method to the list of methods to be added to this class. translatedMethodList = translatedMethodList.prepend(lambdaDecl); - //Step Two: //now that we have generated a method for the lambda expression, //we can translate the lambda into a method reference pointing to the newly //created method. @@ -178,12 +153,12 @@ //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 + // * the "this" argument if it is an instance method + // * enclosing locals captured by the lambda expression ListBuffer<JCExpression> syntheticInits = ListBuffer.lb(); - if (isBound) { + if (!isStatic) { syntheticInits.append(makeThis( lambdaDecl.sym.owner.asType(), localContext.owner)); @@ -201,9 +176,10 @@ List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev); //build a sam instance using an indy call to the meta-factory - int refKind = Pool.MemberReference.methodRefKind(!isBound, localContext.translatedSym.enclClass().isInterface()); + int refKind = Pool.MemberReference.methodRefKind(isStatic, sym.enclClass().isInterface()); - result = makeMetaFactoryIndyCall(tree, tree.targetType, refKind, localContext.translatedSym, indy_args); + //convert to an invokedynamic call + result = makeMetaFactoryIndyCall(tree, tree.targetType, refKind, sym, indy_args); } private JCIdent makeThis(Type type, Symbol owner) { @@ -214,6 +190,11 @@ return make.Ident(_this); } + /** + * Translate a method reference into an invokedynamic call to the + * meta-factory. + * @param tree + */ @Override public void visitReference(JCMemberReference tree) { ReferenceToMethodTranslationContext localContext = (ReferenceToMethodTranslationContext)context; @@ -607,6 +588,13 @@ } @Override + public void visitLambda(JCLambda tree) { + super.visitLambda(tree); + LambdaToMethodTranslationContext context = (LambdaToMethodTranslationContext)contextMap.get(tree); + context.complete(); + } + + @Override public void visitClassDef(JCClassDecl tree) { super.visitClassDef(tree); if (frameStack.nonEmpty() && enclosingLambda() != null) { @@ -682,10 +670,12 @@ }; class LambdaToMethodTranslationContext extends LambdaTranslationContext { + + List<JCVariableDecl> syntheticParams; LambdaToMethodTranslationContext(JCLambda tree) { super(tree); - this.translatedSym = makeSyntheticMethod(STATIC, lambdaName(), null, owner.enclClass()); + this.translatedSym = makeSyntheticMethod(0, lambdaName(), null, owner.enclClass()); } @Override @@ -696,6 +686,38 @@ return makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym); } } + + void complete() { + if (syntheticParams != null) { + return; + } + boolean inInterface = translatedSym.owner.isInterface(); + boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty(); + boolean needInstance = thisReferenced || inInterface; + + // If instance access isn't needed, make it static + // Interface methods much be public default methods, otherwise make it private + translatedSym.flags_field = (needInstance? 0 : STATIC) | (inInterface? PUBLIC | DEFENDER : PRIVATE); + + //compute synthetic params + ListBuffer<JCVariableDecl> params = ListBuffer.lb(); + + // The signature of the 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 + for (Symbol thisSym : getSymbolMap(CAPTURED_VAR, PARAM).values()) { + params.append(make.VarDef((VarSymbol) thisSym, null)); + } + + syntheticParams = params.toList(); + + //prepend synthetic args to translated lambda method signature + translatedSym.type = (MethodType) types.createMethodTypeWithParameters( + (MethodType) generatedLambdaSig(), + TreeInfo.types(syntheticParams)); + } @Override protected Type enclosingType() { @@ -703,7 +725,7 @@ return owner.enclClass().type; } - protected Type generatedLambdaSig() { + private Type generatedLambdaSig() { return types.erasure(types.findDescriptorType(tree.targetType)); } }