src/share/classes/com/sun/tools/javac/comp/Lower.java

Print this page

        

*** 325,334 **** --- 325,353 ---- } else { return List.nil(); } } + static class LambdaFreeVarCollector extends TreeScanner { + private final Symbol owner; + List<VarSymbol> freeVars = List.nil(); + + public LambdaFreeVarCollector(Symbol owner) { + this.owner = owner; + } + + @Override + public void visitIdent(JCIdent tree) { + Symbol sym = tree.sym; + //FIXME Remi: wrong condition, should be investigated + if (sym.kind == VAR && sym.owner.kind == MTH && sym.owner != owner) { + VarSymbol v = (VarSymbol)sym; + freeVars = freeVars.prepend(v); + } + } + } + Map<TypeSymbol,EnumMapping> enumSwitchMap = new LinkedHashMap<TypeSymbol,EnumMapping>(); EnumMapping mapForEnum(DiagnosticPosition pos, TypeSymbol enumClass) { EnumMapping map = enumSwitchMap.get(enumClass); if (map == null)
*** 2388,2397 **** --- 2407,2583 ---- super.visitMethodDef(tree); } result = tree; } + int lambdaNum = 0; + + public void visitLambda(JCLambda tree) { + MethodSymbol symbol = tree.sym; + symbol.name = names.fromString("$lambda$"+lambdaNum++); + symbol.erasure_field = null; + + // collect free variables + LambdaFreeVarCollector freeVarCollector = + new LambdaFreeVarCollector(symbol); + freeVarCollector.scan(tree.bodyOrExpr); + List<VarSymbol> freeVars = freeVarCollector.freeVars; + + //FIXME Remi: should be removed + if (freeVars.nonEmpty()) { + log.rawError(tree.pos, "reference to free variable isn't implemented yet"); + result = make.Erroneous(); + return; + } + + MethodType mtype = (MethodType)symbol.type; + mtype.tag = METHOD; + List<Type> argtypes = mtype.argtypes; + + // freevars are parameters + for(List<VarSymbol> l = freeVars; l.nonEmpty(); l = l.tail) { + VarSymbol v = l.head; + argtypes = argtypes.prepend(v.type); + } + mtype.argtypes = argtypes; + + // create a fake method + JCBlock body; + if (tree.bodyOrExpr.getTag() == JCTree.BLOCK) { + body = (JCBlock) tree.bodyOrExpr; + } else { + JCReturn _return = make.at(tree.pos).Return((JCExpression)tree.bodyOrExpr); + _return.setType(tree.bodyOrExpr.type); + body = make.at(tree.pos).Block(0, List.<JCStatement>of(_return)); + } + + List<Type> varTypes; + if (mtype.restype.tag == TYPEVAR) { + varTypes = List.of(mtype.restype); + } else { + varTypes = List.nil(); + } + for(List<Type> l = mtype.argtypes; l.nonEmpty(); l = l.tail) { + if (l.head.tag == TYPEVAR) + varTypes.prepend(l.head); //FIXME Remi: need to remove duplicate, also remove type variables + } // of current class + + JCMethodDecl method = make.at(tree.pos).MethodDef(make.at(tree.pos).Modifiers(PRIVATE|symbol.flags()), + symbol.name, + make.at(tree.pos).Type(mtype.restype), + make.at(tree.pos).TypeParams(varTypes), + tree.parameters, + List.<JCExpression>nil(), + body, + null); + + Type methodType = (varTypes.isEmpty())? mtype: new ForAll(varTypes, mtype); + method.sym = symbol; + method.type = symbol.type = methodType; + + JCClassDecl classDef = classDef(currentClass); + classDef.defs = classDef.defs.prepend(method); + enterSynthetic(tree.pos(), symbol, currentClass.members()); + + // lower method def + JCMethodDecl prevMethodDef = currentMethodDef; + MethodSymbol prevMethodSym = currentMethodSym; + try { + currentMethodDef = method; + currentMethodSym = symbol; + super.visitMethodDef(method); + } finally { + currentMethodDef = prevMethodDef; + currentMethodSym = prevMethodSym; + } + + // lambda should be lower as a ldc + // but VM support not available on jdk7 VM, we have to wait approval of Da Vinci patches + // so lower into method call on MethodHandles.lookup().bind/findStatic + result = lowerExprLambda(tree.pos, symbol.name, (symbol.flags() & STATIC) != 0, mtype); + } + + private JCTree lowerExprLambda(int lambdaPos, Name lambdaName, boolean isStatic, MethodType functionType) { + MethodSymbol lookupSym = new MethodSymbol(PUBLIC|STATIC, + names.fromString("lookup"), // "lookup" should be interned + new MethodType(METHOD, + List.<Type>nil(), + syms.methodHandlesLookupType, + List.<Type>nil(), + syms.methodClass), + syms.methodHandlesType.tsym); + + JCExpression lookup = make.at(lambdaPos).Select( + make.QualIdent(syms.methodHandlesType.tsym), + lookupSym); + + JCExpression lookupApply = make.Apply(List.<JCExpression>nil(), lookup, List.<JCExpression>nil()); + lookupApply.type = syms.methodHandlesLookupType; + + ListBuffer<JCExpression> rtClasses = ListBuffer.lb(); + rtClasses.append(classOfType(types.erasure(functionType.restype), lookup.pos())); + for(List<Type> l = functionType.argtypes; !l.isEmpty(); l=l.tail) { + rtClasses.append(classOfType(types.erasure(l.head), lookup.pos())); + } + + MethodType makeType = new MethodType(METHOD, + List.of(syms.classType, new ArrayType(syms.classType, syms.arraysType.tsym)), + syms.methodTypeType, + List.<Type>nil(), + syms.methodClass); + MethodSymbol makeSym = new MethodSymbol(PUBLIC|STATIC|VARARGS, + names.fromString("make"), // "make" should be interned + makeType, + syms.methodTypeType.tsym); + + // box varags + List<JCExpression> rtClassList = boxArgs(makeType.argtypes, rtClasses.toList(), syms.classType); + + JCExpression methodTypeMake = make.Select( + make.QualIdent(syms.methodTypeType.tsym), + makeSym); + + JCExpression methodTypeMakeApply = make.Apply(List.<JCExpression>nil(), methodTypeMake, rtClassList); + methodTypeMakeApply.type = syms.methodTypeType; + + MethodSymbol findSym = new MethodSymbol(PUBLIC, + names.fromString((isStatic)?"findStatic":"bind"), // "findStatic"/"bind" should be interned + new MethodType(METHOD, + List.of((isStatic)?syms.classType:syms.objectType, syms.stringType, syms.methodTypeType), + syms.methodHandleType, + List.<Type>nil(), + syms.methodClass), + syms.methodHandlesLookupType.tsym); + + JCExpression findStatic = make.Select( + lookupApply, + findSym); + + JCExpression receiver; + if (isStatic) { + JCFieldAccess thisClass = make.Select(make.Ident(currentClass), names._class); + thisClass.sym = new VarSymbol(STATIC | PUBLIC | FINAL, + names._class, + new ClassType(Type.noType, List.<Type>nil(), syms.classType.tsym), + currentClass); + thisClass.type = thisClass.sym.type; + receiver = thisClass; + } else { + Symbol thissym = rs.resolveSelf(lookup.pos(), attrEnv, currentClass, names._this); + JCIdent thisIdent = make.Ident(thissym); + thisIdent.type = thissym.type; + receiver = thisIdent; + } + + JCLiteral nameLit = make.Literal(TypeTags.CLASS, lambdaName.toString()); + nameLit.type = syms.stringType; + + JCExpression init = make.Apply(List.<JCExpression>nil(), findStatic, List.of(receiver, nameLit, methodTypeMakeApply)); + init.type = syms.methodHandleType; + return init; + } + public void visitAnnotatedType(JCAnnotatedType tree) { tree.underlyingType = translate(tree.underlyingType); result = tree.underlyingType; }
*** 3398,3407 **** --- 3584,3594 ---- outerThisStack = List.nil(); accessNums = new HashMap<Symbol,Integer>(); accessSyms = new HashMap<Symbol,MethodSymbol[]>(); accessConstrs = new HashMap<Symbol,MethodSymbol>(); accessed = new ListBuffer<Symbol>(); + lambdaNum = 0; translate(cdef, (JCExpression)null); for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail) makeAccessible(l.head); for (EnumMapping map : enumSwitchMap.values()) map.translate();