8114838: Anonymous functions escape to surrounding scope when defined under "with" statement

Reviewed-by: attila, hannesw, lagergren
This commit is contained in:
Athijegannathan Sundararajan 2015-06-30 13:10:37 +05:30
parent 74b5de9db2
commit d9a4c01c25
11 changed files with 216 additions and 18 deletions

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// bind on a Java method
// #javascript "bind" function
var bind = Function.prototype.bind;
// Java console object
var console = java.lang.System.console();
// arguments "this" and prompt string of Console.readLine method are bound
var readName = bind.call(console.readLine, console, "Your name: ");
// Now call it like a function that takes no arguments!
print("Hello,", readName());

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// bind on a Java constructor
// See Function.prototype.bind:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
var bind = Function.prototype.bind;
var URL = Java.type("java.net.URL");
// get the constructor that accepts URL, String parameters.
// constructor signatures are properties of type object.
var newURL = URL["(URL, String)"];
// bind "context" URL parameter.
var TwitterURL = bind.call(newURL, null, new URL('https://www.twitter.com'));
// now you can create context relative URLs using the bound constructor
print(new TwitterURL("sundararajan_a"));
// read the URL content and print (optional part)
var BufferedReader = Java.type("java.io.BufferedReader");
var InputStreamReader = Java.type("java.io.InputStreamReader");
// function to retrieve text content of the given URL
function readTextFromURL(url) {
var str = '';
var u = new URL(url);
var reader = new BufferedReader(
new InputStreamReader(u.openStream()));
try {
reader.lines().forEach(function(x) str += x);
return str;
} finally {
reader.close();
}
}
print(readTextFromURL(new TwitterURL("sundararajan_a")));

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Using a Java map with Javascript "with" statement
var map = new java.util.HashMap();
map.put("foo", 34);
map.put("bar", "hello");
var obj = {
__noSuchProperty__: function(name) {
return map.get(name);
}
};
with(obj) {
print(foo);
print(bar);
}

View File

@ -40,7 +40,7 @@ final class FunctionExpressionTreeImpl extends ExpressionTreeImpl
final BlockTree body) {
super(node);
funcNode = node;
assert !funcNode.isDeclared() : "function expression expected";
assert !funcNode.isDeclared() || funcNode.isAnonymous() : "function expression expected";
final FunctionNode.Kind kind = node.getKind();
if (node.isAnonymous() || kind == FunctionNode.Kind.GETTER || kind == FunctionNode.Kind.SETTER) {

View File

@ -224,7 +224,7 @@ final class IRTranslator extends NodeVisitor<LexicalContext> {
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
assert !functionNode.isDeclared() : "should not reach here for function declaration";
assert !functionNode.isDeclared() || functionNode.isAnonymous() : "should not reach here for function declaration";
final List<? extends ExpressionTree> paramTrees
= translateExprs(functionNode.getParameters());

View File

@ -551,9 +551,7 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
private void defineVarIdent(final VarNode varNode) {
final IdentNode ident = varNode.getName();
final int flags;
if (varNode.isAnonymousFunctionDeclaration()) {
flags = IS_INTERNAL;
} else if (!varNode.isBlockScoped() && lc.getCurrentFunction().isProgram()) {
if (!varNode.isBlockScoped() && lc.getCurrentFunction().isProgram()) {
flags = IS_SCOPE;
} else {
flags = 0;

View File

@ -312,10 +312,6 @@ final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> {
assert !varNode.isBlockScoped(); //TODO: we must handle these too, but we currently don't
final Expression init = varNode.getInit();
if (varNode.isAnonymousFunctionDeclaration()) {
// We ain't moving anonymous function declarations.
return super.enterVarNode(varNode);
}
// Move a declaration-only var statement to the top of the outermost function.
getCurrentFunctionState().varStatements.add(varNode.setInit(null));

View File

@ -290,12 +290,4 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
public boolean isFunctionDeclaration() {
return init instanceof FunctionNode && ((FunctionNode)init).isDeclared();
}
/**
* Returns true if this is an anonymous function declaration.
* @return true if this is an anonymous function declaration.
*/
public boolean isAnonymousFunctionDeclaration() {
return isFunctionDeclaration() && ((FunctionNode)init).isAnonymous();
}
}

View File

@ -2765,6 +2765,11 @@ loop:
functionBody);
if (isStatement) {
if (isAnonymous) {
appendStatement(new ExpressionStatement(functionLine, functionToken, finish, function));
return function;
}
// mark ES6 block functions as lexically scoped
final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET;
final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags);

View File

@ -40,4 +40,4 @@ function(x) {
EOF, print);
Assert.assertNull(ast.sourceElements[0].name);
Assert.assertNull(ast.sourceElements[0].expression.name);

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2015 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-8114838: Anonymous functions escape to surrounding scope when defined under "with" statement
*
* @test
* @run
*/
// do *not* introduce new lines! The next line should be 32
with({}) { function () {} }
if (typeof this["L:32"] != 'undefined') {
throw new Error("anonymous name spills into global scope");
}
var func = eval("function() {}");
if (typeof func != 'function') {
throw new Error("eval of anonymous function does not work!");
}
var ScriptEngineManager = Java.type("javax.script.ScriptEngineManager");
var engine = new ScriptEngineManager().getEngineByName("nashorn");
var func2 = engine.eval("function() {}");
if (typeof func2 != 'function') {
throw new Error("eval of anonymous function does not work from script engine!");
}