8019822: Duplicate name and signature in finally block
Reviewed-by: jlaskey, sundar
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Jul 12 15:27:16 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Jul 12 11:58:42 2013 +0200
@@ -55,10 +55,12 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
import java.util.TreeMap;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@@ -184,6 +186,8 @@
/** From what size should we use spill instead of fields for JavaScript objects? */
private static final int OBJECT_SPILL_THRESHOLD = 300;
+ private final Set<String> emittedMethods = new HashSet<>();
+
/**
* Constructor.
*
@@ -490,6 +494,9 @@
@Override
public boolean enterBlock(final Block block) {
+ if(lc.isFunctionBody() && emittedMethods.contains(lc.getCurrentFunction().getName())) {
+ return false;
+ }
method.label(block.getEntryLabel());
initLocals(block);
@@ -1007,17 +1014,28 @@
return false;
}
- LOG.info("=== BEGIN ", functionNode.getName());
-
- assert functionNode.getCompileUnit() != null : "no compile unit for " + functionNode.getName() + " " + Debug.id(functionNode);
- unit = lc.pushCompileUnit(functionNode.getCompileUnit());
- assert lc.hasCompileUnits();
-
- method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode));
- // new method - reset last line number
- lastLineNumber = -1;
- // Mark end for variable tables.
- method.begin();
+ final String fnName = functionNode.getName();
+ // NOTE: we only emit the method for a function with the given name once. We can have multiple functions with
+ // the same name as a result of inlining finally blocks. However, in the future -- with type specialization,
+ // notably -- we might need to check for both name *and* signature. Of course, even that might not be
+ // sufficient; the function might have a code dependency on the type of the variables in its enclosing scopes,
+ // and the type of such a variable can be different in catch and finally blocks. So, in the future we will have
+ // to decide to either generate a unique method for each inlined copy of the function, maybe figure out its
+ // exact type closure and deduplicate based on that, or just decide that functions in finally blocks aren't
+ // worth it, and generate one method with most generic type closure.
+ if(!emittedMethods.contains(fnName)) {
+ LOG.info("=== BEGIN ", fnName);
+
+ assert functionNode.getCompileUnit() != null : "no compile unit for " + fnName + " " + Debug.id(functionNode);
+ unit = lc.pushCompileUnit(functionNode.getCompileUnit());
+ assert lc.hasCompileUnits();
+
+ method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode));
+ // new method - reset last line number
+ lastLineNumber = -1;
+ // Mark end for variable tables.
+ method.begin();
+ }
return true;
}
@@ -1025,13 +1043,14 @@
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
try {
- method.end(); // wrap up this method
- unit = lc.popCompileUnit(functionNode.getCompileUnit());
- method = lc.popMethodEmitter(method);
- LOG.info("=== END ", functionNode.getName());
+ if(emittedMethods.add(functionNode.getName())) {
+ method.end(); // wrap up this method
+ unit = lc.popCompileUnit(functionNode.getCompileUnit());
+ method = lc.popMethodEmitter(method);
+ LOG.info("=== END ", functionNode.getName());
+ }
final FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED);
-
newFunctionObject(newFunctionNode, functionNode);
return newFunctionNode;
} catch (final Throwable t) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8019822.js Fri Jul 12 11:58:42 2013 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2010, 2013, 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.
+ */
+
+/**
+ * JDK-8019822: Duplicate name/signature for a function in finally block
+ *
+ * @test
+ */
+try { function (x) /x/ } finally { (function(id) { return id }); }