336 if (fv != localContext.self) { |
336 if (fv != localContext.self) { |
337 JCTree captured_local = make.Ident(fv).setType(fv.type); |
337 JCTree captured_local = make.Ident(fv).setType(fv.type); |
338 syntheticInits.append((JCExpression) captured_local); |
338 syntheticInits.append((JCExpression) captured_local); |
339 } |
339 } |
340 } |
340 } |
|
341 // add captured outer this instances (used only when `this' capture itself is illegal) |
|
342 for (Symbol fv : localContext.getSymbolMap(CAPTURED_OUTER_THIS).keySet()) { |
|
343 JCTree captured_local = make.QualThis(fv.type); |
|
344 syntheticInits.append((JCExpression) captured_local); |
|
345 } |
341 |
346 |
342 //then, determine the arguments to the indy call |
347 //then, determine the arguments to the indy call |
343 List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev); |
348 List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev); |
344 |
349 |
345 //build a sam instance using an indy call to the meta-factory |
350 //build a sam instance using an indy call to the meta-factory |
425 result = ltree; |
430 result = ltree; |
426 } else { |
431 } else { |
427 //access to untranslated symbols (i.e. compile-time constants, |
432 //access to untranslated symbols (i.e. compile-time constants, |
428 //members defined inside the lambda body, etc.) ) |
433 //members defined inside the lambda body, etc.) ) |
429 super.visitIdent(tree); |
434 super.visitIdent(tree); |
|
435 } |
|
436 } finally { |
|
437 make.at(prevPos); |
|
438 } |
|
439 } |
|
440 } |
|
441 |
|
442 /** |
|
443 * Translate qualified `this' references within a lambda to the mapped identifier |
|
444 * @param tree |
|
445 */ |
|
446 @Override |
|
447 public void visitSelect(JCFieldAccess tree) { |
|
448 if (context == null || !analyzer.lambdaFieldAccessFilter(tree)) { |
|
449 super.visitSelect(tree); |
|
450 } else { |
|
451 int prevPos = make.pos; |
|
452 try { |
|
453 make.at(tree); |
|
454 |
|
455 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context; |
|
456 JCTree ltree = lambdaContext.translate(tree); |
|
457 if (ltree != null) { |
|
458 result = ltree; |
|
459 } else { |
|
460 super.visitSelect(tree); |
430 } |
461 } |
431 } finally { |
462 } finally { |
432 make.at(prevPos); |
463 make.at(prevPos); |
433 } |
464 } |
434 } |
465 } |
1124 * names) |
1155 * names) |
1125 */ |
1156 */ |
1126 private int lambdaCount = 0; |
1157 private int lambdaCount = 0; |
1127 |
1158 |
1128 /** |
1159 /** |
|
1160 * List of types undergoing construction via explicit constructor chaining. |
|
1161 */ |
|
1162 private List<ClassSymbol> typesUnderConstruction; |
|
1163 |
|
1164 /** |
1129 * keep the count of lambda expression defined in given context (used to |
1165 * keep the count of lambda expression defined in given context (used to |
1130 * generate unambiguous names for serializable lambdas) |
1166 * generate unambiguous names for serializable lambdas) |
1131 */ |
1167 */ |
1132 private class SyntheticMethodNameCounter { |
1168 private class SyntheticMethodNameCounter { |
1133 private Map<String, Integer> map = new HashMap<>(); |
1169 private Map<String, Integer> map = new HashMap<>(); |
1154 private Map<ClassSymbol, Symbol> clinits = |
1190 private Map<ClassSymbol, Symbol> clinits = |
1155 new HashMap<ClassSymbol, Symbol>(); |
1191 new HashMap<ClassSymbol, Symbol>(); |
1156 |
1192 |
1157 private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) { |
1193 private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) { |
1158 frameStack = List.nil(); |
1194 frameStack = List.nil(); |
|
1195 typesUnderConstruction = List.nil(); |
1159 localClassDefs = new HashMap<Symbol, JCClassDecl>(); |
1196 localClassDefs = new HashMap<Symbol, JCClassDecl>(); |
1160 return translate(tree); |
1197 return translate(tree); |
1161 } |
1198 } |
|
1199 |
|
1200 @Override |
|
1201 public void visitApply(JCMethodInvocation tree) { |
|
1202 List<ClassSymbol> previousNascentTypes = typesUnderConstruction; |
|
1203 try { |
|
1204 Name methName = TreeInfo.name(tree.meth); |
|
1205 if (methName == names._this || methName == names._super) { |
|
1206 typesUnderConstruction = typesUnderConstruction.prepend(currentClass()); |
|
1207 } |
|
1208 super.visitApply(tree); |
|
1209 } finally { |
|
1210 typesUnderConstruction = previousNascentTypes; |
|
1211 } |
|
1212 } |
|
1213 // where |
|
1214 private ClassSymbol currentClass() { |
|
1215 for (Frame frame : frameStack) { |
|
1216 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) { |
|
1217 JCClassDecl cdef = (JCClassDecl) frame.tree; |
|
1218 return cdef.sym; |
|
1219 } |
|
1220 } |
|
1221 return null; |
|
1222 } |
1162 |
1223 |
1163 @Override |
1224 @Override |
1164 public void visitBlock(JCBlock tree) { |
1225 public void visitBlock(JCBlock tree) { |
1165 List<Frame> prevStack = frameStack; |
1226 List<Frame> prevStack = frameStack; |
1166 try { |
1227 try { |
1622 && !sym.isStatic() |
1683 && !sym.isStatic() |
1623 && sym.name != names.init; |
1684 && sym.name != names.init; |
1624 } |
1685 } |
1625 |
1686 |
1626 /** |
1687 /** |
|
1688 * This is used to filter out those select nodes that need to be adjusted |
|
1689 * when translating away lambda expressions - at the moment, this is the |
|
1690 * set of nodes that select `this' (qualified this) |
|
1691 */ |
|
1692 private boolean lambdaFieldAccessFilter(JCFieldAccess fAccess) { |
|
1693 LambdaTranslationContext lambdaContext = |
|
1694 context instanceof LambdaTranslationContext ? |
|
1695 (LambdaTranslationContext) context : null; |
|
1696 return lambdaContext != null |
|
1697 && !fAccess.sym.isStatic() |
|
1698 && fAccess.name == names._this |
|
1699 && (fAccess.sym.owner.kind == TYP) |
|
1700 && !lambdaContext.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty(); |
|
1701 } |
|
1702 |
|
1703 /** |
1627 * This is used to filter out those new class expressions that need to |
1704 * This is used to filter out those new class expressions that need to |
1628 * be qualified with an enclosing tree |
1705 * be qualified with an enclosing tree |
1629 */ |
1706 */ |
1630 private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) { |
1707 private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) { |
1631 if (context != null |
1708 if (context != null |
1795 |
1872 |
1796 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>()); |
1873 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>()); |
1797 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>()); |
1874 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>()); |
1798 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>()); |
1875 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>()); |
1799 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>()); |
1876 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>()); |
|
1877 translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>()); |
1800 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>()); |
1878 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>()); |
1801 |
1879 |
1802 freeVarProcessedLocalClasses = new HashSet<>(); |
1880 freeVarProcessedLocalClasses = new HashSet<>(); |
1803 } |
1881 } |
1804 |
1882 |
1907 //keep mapping with original captured symbol |
1985 //keep mapping with original captured symbol |
1908 return sym; |
1986 return sym; |
1909 } |
1987 } |
1910 }; |
1988 }; |
1911 break; |
1989 break; |
|
1990 case CAPTURED_OUTER_THIS: |
|
1991 Name name = names.fromString(new String(sym.flatName().toString() + names.dollarThis)); |
|
1992 ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) { |
|
1993 @Override |
|
1994 public Symbol baseSymbol() { |
|
1995 //keep mapping with original captured symbol |
|
1996 return sym; |
|
1997 } |
|
1998 }; |
|
1999 break; |
1912 case LOCAL_VAR: |
2000 case LOCAL_VAR: |
1913 ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym); |
2001 ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym); |
1914 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; |
2002 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; |
1915 break; |
2003 break; |
1916 case PARAM: |
2004 case PARAM: |
1927 } |
2015 } |
1928 return ret; |
2016 return ret; |
1929 } |
2017 } |
1930 |
2018 |
1931 void addSymbol(Symbol sym, LambdaSymbolKind skind) { |
2019 void addSymbol(Symbol sym, LambdaSymbolKind skind) { |
|
2020 if (skind == CAPTURED_THIS && sym != null && sym.kind == TYP && !typesUnderConstruction.isEmpty()) { |
|
2021 ClassSymbol currentClass = currentClass(); |
|
2022 if (currentClass != null && typesUnderConstruction.contains(currentClass)) { |
|
2023 // reference must be to enclosing outer instance, mutate capture kind. |
|
2024 Assert.check(sym != currentClass); // should have been caught right in Attr |
|
2025 skind = CAPTURED_OUTER_THIS; |
|
2026 } |
|
2027 } |
1932 Map<Symbol, Symbol> transMap = getSymbolMap(skind); |
2028 Map<Symbol, Symbol> transMap = getSymbolMap(skind); |
1933 if (!transMap.containsKey(sym)) { |
2029 if (!transMap.containsKey(sym)) { |
1934 transMap.put(sym, translate(sym, skind)); |
2030 transMap.put(sym, translate(sym, skind)); |
1935 } |
2031 } |
1936 } |
2032 } |
1940 Assert.checkNonNull(m); |
2036 Assert.checkNonNull(m); |
1941 return m; |
2037 return m; |
1942 } |
2038 } |
1943 |
2039 |
1944 JCTree translate(JCIdent lambdaIdent) { |
2040 JCTree translate(JCIdent lambdaIdent) { |
1945 for (Map<Symbol, Symbol> m : translatedSymbols.values()) { |
2041 for (LambdaSymbolKind kind : LambdaSymbolKind.values()) { |
1946 if (m.containsKey(lambdaIdent.sym)) { |
2042 Map<Symbol, Symbol> m = getSymbolMap(kind); |
1947 Symbol tSym = m.get(lambdaIdent.sym); |
2043 switch(kind) { |
1948 JCTree t = make.Ident(tSym).setType(lambdaIdent.type); |
2044 default: |
1949 tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes()); |
2045 if (m.containsKey(lambdaIdent.sym)) { |
1950 return t; |
2046 Symbol tSym = m.get(lambdaIdent.sym); |
|
2047 JCTree t = make.Ident(tSym).setType(lambdaIdent.type); |
|
2048 tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes()); |
|
2049 return t; |
|
2050 } |
|
2051 break; |
|
2052 case CAPTURED_OUTER_THIS: |
|
2053 if (lambdaIdent.sym.owner.kind == TYP && m.containsKey(lambdaIdent.sym.owner)) { |
|
2054 // Transform outer instance variable references anchoring them to the captured synthetic. |
|
2055 Symbol tSym = m.get(lambdaIdent.sym.owner); |
|
2056 JCExpression t = make.Ident(tSym).setType(lambdaIdent.sym.owner.type); |
|
2057 tSym.setTypeAttributes(lambdaIdent.sym.owner.getRawTypeAttributes()); |
|
2058 t = make.Select(t, lambdaIdent.name); |
|
2059 t.setType(lambdaIdent.type); |
|
2060 TreeInfo.setSymbol(t, lambdaIdent.sym); |
|
2061 return t; |
|
2062 } |
|
2063 break; |
1951 } |
2064 } |
|
2065 } |
|
2066 return null; |
|
2067 } |
|
2068 |
|
2069 /* Translate away qualified this expressions, anchoring them to synthetic parameters that |
|
2070 capture the qualified this handle. `fieldAccess' is guaranteed to one such. |
|
2071 */ |
|
2072 public JCTree translate(JCFieldAccess fieldAccess) { |
|
2073 Assert.check(fieldAccess.name == names._this); |
|
2074 Map<Symbol, Symbol> m = translatedSymbols.get(LambdaSymbolKind.CAPTURED_OUTER_THIS); |
|
2075 if (m.containsKey(fieldAccess.sym.owner)) { |
|
2076 Symbol tSym = m.get(fieldAccess.sym.owner); |
|
2077 JCExpression t = make.Ident(tSym).setType(fieldAccess.sym.owner.type); |
|
2078 tSym.setTypeAttributes(fieldAccess.sym.owner.getRawTypeAttributes()); |
|
2079 return t; |
1952 } |
2080 } |
1953 return null; |
2081 return null; |
1954 } |
2082 } |
1955 |
2083 |
1956 /** |
2084 /** |
1985 // synthetic parameters: |
2113 // synthetic parameters: |
1986 // |
2114 // |
1987 // 1) reference to enclosing contexts captured by the lambda expression |
2115 // 1) reference to enclosing contexts captured by the lambda expression |
1988 // 2) enclosing locals captured by the lambda expression |
2116 // 2) enclosing locals captured by the lambda expression |
1989 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) { |
2117 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) { |
|
2118 params.append(make.VarDef((VarSymbol) thisSym, null)); |
|
2119 parameterSymbols.append((VarSymbol) thisSym); |
|
2120 } |
|
2121 for (Symbol thisSym : getSymbolMap(CAPTURED_OUTER_THIS).values()) { |
1990 params.append(make.VarDef((VarSymbol) thisSym, null)); |
2122 params.append(make.VarDef((VarSymbol) thisSym, null)); |
1991 parameterSymbols.append((VarSymbol) thisSym); |
2123 parameterSymbols.append((VarSymbol) thisSym); |
1992 } |
2124 } |
1993 for (Symbol thisSym : getSymbolMap(PARAM).values()) { |
2125 for (Symbol thisSym : getSymbolMap(PARAM).values()) { |
1994 params.append(make.VarDef((VarSymbol) thisSym, null)); |
2126 params.append(make.VarDef((VarSymbol) thisSym, null)); |
2136 enum LambdaSymbolKind { |
2268 enum LambdaSymbolKind { |
2137 PARAM, // original to translated lambda parameters |
2269 PARAM, // original to translated lambda parameters |
2138 LOCAL_VAR, // original to translated lambda locals |
2270 LOCAL_VAR, // original to translated lambda locals |
2139 CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters |
2271 CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters |
2140 CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access) |
2272 CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access) |
|
2273 CAPTURED_OUTER_THIS, // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740) |
2141 TYPE_VAR; // original to translated lambda type variables |
2274 TYPE_VAR; // original to translated lambda type variables |
2142 } |
2275 } |
2143 |
2276 |
2144 /** |
2277 /** |
2145 * **************************************************************** |
2278 * **************************************************************** |