8169345: javac crash when local from enclosing context is captured multiple times
Summary: captured variables imported from multiple enclosing scopes are not handled correctly
Reviewed-by: vromero
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Mon Oct 09 17:37:15 2017 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Mon Oct 09 13:03:18 2017 +0100
@@ -308,8 +308,8 @@
void visitSymbol(Symbol _sym) {
Symbol sym = _sym;
if (sym.kind == VAR || sym.kind == MTH) {
- while (sym != null && sym.owner != owner)
- sym = proxies.findFirst(proxyName(sym.name));
+ if (sym != null && sym.owner != owner)
+ sym = proxies.get(sym);
if (sym != null && sym.owner == owner) {
VarSymbol v = (VarSymbol)sym;
if (v.getConstValue() == null) {
@@ -1084,7 +1084,7 @@
return makeLit(sym.type, cv);
}
// Otherwise replace the variable by its proxy.
- sym = proxies.findFirst(proxyName(sym.name));
+ sym = proxies.get(sym);
Assert.check(sym != null && (sym.flags_field & FINAL) != 0);
tree = make.at(tree.pos).Ident(sym);
}
@@ -1359,14 +1359,12 @@
* Free variables proxies and this$n
*************************************************************************/
- /** A scope containing all free variable proxies for currently translated
- * class, as well as its this$n symbol (if needed).
- * Proxy scopes are nested in the same way classes are.
- * Inside a constructor, proxies and any this$n symbol are duplicated
- * in an additional innermost scope, where they represent the constructor
- * parameters.
+ /** A map which allows to retrieve the translated proxy variable for any given symbol of an
+ * enclosing scope that is accessed (the accessed symbol could be the synthetic 'this$n' symbol).
+ * Inside a constructor, the map temporarily overrides entries corresponding to proxies and any
+ * 'this$n' symbols, where they represent the constructor parameters.
*/
- WriteableScope proxies;
+ Map<Symbol, Symbol> proxies;
/** A scope containing all unnamed resource variables/saved
* exception variables for translated TWR blocks
@@ -1383,8 +1381,12 @@
/** The name of a free variable proxy.
*/
- Name proxyName(Name name) {
- return names.fromString("val" + target.syntheticNameChar() + name);
+ Name proxyName(Name name, int index) {
+ Name proxyName = names.fromString("val" + target.syntheticNameChar() + name);
+ if (index > 0) {
+ proxyName = proxyName.append(names.fromString("" + target.syntheticNameChar() + index));
+ }
+ return proxyName;
}
/** Proxy definitions for all free variables in given list, in reverse order.
@@ -1400,11 +1402,17 @@
long additionalFlags) {
long flags = FINAL | SYNTHETIC | additionalFlags;
List<JCVariableDecl> defs = List.nil();
+ Set<Name> proxyNames = new HashSet<>();
for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
VarSymbol v = l.head;
+ int index = 0;
+ Name proxyName;
+ do {
+ proxyName = proxyName(v.name, index++);
+ } while (!proxyNames.add(proxyName));
VarSymbol proxy = new VarSymbol(
- flags, proxyName(v.name), v.erasure(types), owner);
- proxies.enter(proxy);
+ flags, proxyName, v.erasure(types), owner);
+ proxies.put(v, proxy);
JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
vd.vartype = access(vd.vartype);
defs = defs.prepend(vd);
@@ -1843,11 +1851,8 @@
/** Return tree simulating the assignment {@code this.name = name}, where
* name is the name of a free variable.
*/
- JCStatement initField(int pos, Name name) {
- Iterator<Symbol> it = proxies.getSymbolsByName(name).iterator();
- Symbol rhs = it.next();
+ JCStatement initField(int pos, Symbol rhs, Symbol lhs) {
Assert.check(rhs.owner.kind == MTH);
- Symbol lhs = it.next();
Assert.check(rhs.owner.owner == lhs.owner);
make.at(pos);
return
@@ -2207,7 +2212,8 @@
classdefs.put(currentClass, tree);
- proxies = proxies.dup(currentClass);
+ Map<Symbol, Symbol> prevProxies = proxies;
+ proxies = new HashMap<>(proxies);
List<VarSymbol> prevOuterThisStack = outerThisStack;
// If this is an enum definition
@@ -2270,7 +2276,7 @@
enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
}
- proxies = proxies.leave();
+ proxies = prevProxies;
outerThisStack = prevOuterThisStack;
// Append translated tree to `translated' queue.
@@ -2488,7 +2494,8 @@
// Push a new proxy scope for constructor parameters.
// and create definitions for any this$n and proxy parameters.
- proxies = proxies.dup(m);
+ Map<Symbol, Symbol> prevProxies = proxies;
+ proxies = new HashMap<>(proxies);
List<VarSymbol> prevOuterThisStack = outerThisStack;
List<VarSymbol> fvs = freevars(currentClass);
JCVariableDecl otdef = null;
@@ -2523,13 +2530,12 @@
if (fvs.nonEmpty()) {
List<Type> addedargtypes = List.nil();
for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
- final Name pName = proxyName(l.head.name);
m.capturedLocals =
m.capturedLocals.prepend((VarSymbol)
- (proxies.findFirst(pName)));
+ (proxies.get(l.head)));
if (TreeInfo.isInitialConstructor(tree)) {
added = added.prepend(
- initField(tree.body.pos, pName));
+ initField(tree.body.pos, proxies.get(l.head), prevProxies.get(l.head)));
}
addedargtypes = addedargtypes.prepend(l.head.erasure(types));
}
@@ -2547,7 +2553,7 @@
}
// pop local variables from proxy stack
- proxies = proxies.leave();
+ proxies = prevProxies;
// recursively translate following local statements and
// combine with this- or super-call
@@ -3714,7 +3720,7 @@
classdefs = new HashMap<>();
actualSymbols = new HashMap<>();
freevarCache = new HashMap<>();
- proxies = WriteableScope.create(syms.noSymbol);
+ proxies = new HashMap<>();
twrVars = WriteableScope.create(syms.noSymbol);
outerThisStack = List.nil();
accessNums = new HashMap<>();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/8169345/T8169345a.java Mon Oct 09 13:03:18 2017 +0100
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, 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
+ * @bug 8169345
+ * @summary javac crash when local from enclosing context is captured multiple times
+ */
+
+public class T8169345a {
+ void test() {
+ Object o = new Object();
+ class Local1 {
+ Object test1() {
+ return o;
+ }
+ }
+ class Local2 {
+ void test2() {
+ Object o = new Object();
+ class Local3 extends Local1 {
+ Object test3() {
+ return o;
+ }
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ Class.forName("T8169345a$1Local1");
+ Class.forName("T8169345a$1Local2$1Local3");
+ Class.forName("T8169345a$1Local2");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/8169345/T8169345b.java Mon Oct 09 13:03:18 2017 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+/*
+ * @test
+ * @bug 8169345
+ * @summary javac crash when local from enclosing context is captured multiple times
+ */
+
+public class T8169345b {
+ void test() {
+ Object o = new Object();
+ class Local1 {
+ Object test1() {
+ return o;
+ }
+ }
+ class Local2 {
+ void test2() {
+ Object o = new Object();
+ class Local3 {
+ Object test3() {
+ return o;
+ }
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ Class.forName("T8169345b$1Local1");
+ Class.forName("T8169345b$1Local2$1Local3");
+ Class.forName("T8169345b$1Local2");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/8169345/T8169345c.java Mon Oct 09 13:03:18 2017 +0100
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+/*
+ * @test
+ * @bug 8169345
+ * @summary javac crash when local from enclosing context is captured multiple times
+ * @compile T8169345c.java
+ */
+
+class T8169345c {
+ void test() {
+ final int b;
+ b = 10;
+ class Local1 {
+ public String toString() {
+ return "" + b;
+ }
+ }
+ class Local2 {
+ void test() {
+ final int b;
+ b = 20;
+ class DeepLocal extends Local1 {
+ public String toString() {
+ return "" + b;
+ }
+ }
+ }
+ }
+ }
+}