# HG changeset patch # User lana # Date 1364324880 25200 # Node ID db8a33cb22b857317edee903fa0f8a4857489280 # Parent 053d7c55dc8272b58b8bb870dc92a4acf896d52a# Parent ed60078f0a80b51aa00c90d5abd4e79dd9d5ddf3 Merge diff -r 053d7c55dc82 -r db8a33cb22b8 bin/jjs --- a/bin/jjs Thu Mar 21 10:43:41 2013 -0700 +++ b/bin/jjs Tue Mar 26 12:08:00 2013 -0700 @@ -26,4 +26,4 @@ [ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; -$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $* +$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $* diff -r 053d7c55dc82 -r db8a33cb22b8 bin/jjssecure --- a/bin/jjssecure Thu Mar 21 10:43:41 2013 -0700 +++ b/bin/jjssecure Tue Mar 26 12:08:00 2013 -0700 @@ -26,4 +26,4 @@ [ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; -$JAVA_HOME/bin/java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.security.properties=`dirname $0`/../make/java.security.override -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=true -Dnashorn.home=`dirname $0`/.. -Djava.security.manager jdk.nashorn.tools.Shell $* +$JAVA_HOME/bin/java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.security.properties=`dirname $0`/../make/java.security.override -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=true -Dnashorn.home=`dirname $0`/.. -Djava.security.manager jdk.nashorn.tools.Shell $* diff -r 053d7c55dc82 -r db8a33cb22b8 bin/nashorn --- a/bin/nashorn Thu Mar 21 10:43:41 2013 -0700 +++ b/bin/nashorn Tue Mar 26 12:08:00 2013 -0700 @@ -26,4 +26,4 @@ [ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; -$JAVA_HOME/bin/jrunscript -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $* +$JAVA_HOME/bin/jrunscript -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $* diff -r 053d7c55dc82 -r db8a33cb22b8 bin/nashornsecure --- a/bin/nashornsecure Thu Mar 21 10:43:41 2013 -0700 +++ b/bin/nashornsecure Tue Mar 26 12:08:00 2013 -0700 @@ -26,4 +26,4 @@ [ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; -$JAVA_HOME/bin/jrunscript -J-Djava.security.properties=`dirname $0`/../make/java.security.override -J-Djava.security.manager -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $* +$JAVA_HOME/bin/jrunscript -J-Djava.security.properties=`dirname $0`/../make/java.security.override -J-Djava.security.manager -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $* diff -r 053d7c55dc82 -r db8a33cb22b8 docs/DEVELOPER_README --- a/docs/DEVELOPER_README Thu Mar 21 10:43:41 2013 -0700 +++ b/docs/DEVELOPER_README Tue Mar 26 12:08:00 2013 -0700 @@ -13,6 +13,17 @@ This documentation of the system property flags assume that the default value of the flag is false, unless otherwise specified. +SYSTEM PROPERTY: -Dnashorn.args= + +This property takes as its value a space separated list of Nashorn +command line options that should be passed to Nashorn. This might be useful +in environments where it is hard to tell how a nashorn.jar is launched. + +Example: + +> java -Dnashorn.args="--lazy-complation --log=compiler" large-java-app-with-nashorn.jar +> ant -Dnashorn.args="--log=codegen" antjob + SYSTEM PROPERTY: -Dnashorn.unstable.relink.threshold=x This property controls how many call site misses are allowed before a diff -r 053d7c55dc82 -r db8a33cb22b8 docs/JavaScriptingProgrammersGuide.html --- a/docs/JavaScriptingProgrammersGuide.html Thu Mar 21 10:43:41 2013 -0700 +++ b/docs/JavaScriptingProgrammersGuide.html Tue Mar 26 12:08:00 2013 -0700 @@ -533,9 +533,8 @@

Creating, Converting and Using Java Arrays

-

While creating a Java object is the same as in Java, to create -Java arrays in JavaScript we can use Java reflection -explicitly. But once created the element access or length access is +

+Array element access or length access is the same as in Java. Also, a script array can be used when a Java method expects a Java array (auto conversion). So in most cases we don't have to create Java arrays explicitly.

@@ -543,7 +542,8 @@ // javaarray.js // create Java String array of 5 elements -var a = java.lang.reflect.Array.newInstance(java.lang.String.class, 5); +var StringArray = Java.type("java.lang.String[]"); +var a = new StringArray(5); // Accessing elements and length access is by usual Java syntax a[0] = "scripting is great!"; diff -r 053d7c55dc82 -r db8a33cb22b8 docs/source/javaarray.js --- a/docs/source/javaarray.js Thu Mar 21 10:43:41 2013 -0700 +++ b/docs/source/javaarray.js Tue Mar 26 12:08:00 2013 -0700 @@ -30,7 +30,8 @@ */ // create Java String array of 5 elements -var a = java.lang.reflect.Array.newInstance(java.lang.String.class, 5); +var StringArray = Java.type("java.lang.String[]"); +var a = new StringArray(5); // Accessing elements and length access is by usual Java syntax a[0] = "scripting is great!"; diff -r 053d7c55dc82 -r db8a33cb22b8 make/build.xml --- a/make/build.xml Thu Mar 21 10:43:41 2013 -0700 +++ b/make/build.xml Tue Mar 26 12:08:00 2013 -0700 @@ -124,7 +124,7 @@ - + @@ -191,12 +191,12 @@ - + - + diff -r 053d7c55dc82 -r db8a33cb22b8 make/code_coverage.xml --- a/make/code_coverage.xml Thu Mar 21 10:43:41 2013 -0700 +++ b/make/code_coverage.xml Tue Mar 26 12:08:00 2013 -0700 @@ -36,7 +36,12 @@ + + + + + @@ -51,25 +56,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - + + + + - + @@ -81,12 +127,12 @@ - + - + diff -r 053d7c55dc82 -r db8a33cb22b8 make/java.security.override --- a/make/java.security.override Thu Mar 21 10:43:41 2013 -0700 +++ b/make/java.security.override Tue Mar 26 12:08:00 2013 -0700 @@ -3,7 +3,7 @@ # We ensure that by overriding "package.access" security property. # The following "package.access" value was copied from default java.security -# of jre/lib/security and appended with nashorn IR, Codegen and Parser packages. +# of jre/lib/security and appended with nashorn sensitive packages. # # List of comma-separated packages that start with or equal this string @@ -11,4 +11,4 @@ # passed to checkPackageAccess unless the # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. -package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal.,jdk.internal.,jdk.nashorn.internal.ir., jdk.nashorn.internal.codegen., jdk.nashorn.internal.lookup., jdk.nashorn.internal.parser. +package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal.,jdk.internal.,jdk.nashorn.internal.,jdk.nashorn.tools. diff -r 053d7c55dc82 -r db8a33cb22b8 make/project.properties --- a/make/project.properties Thu Mar 21 10:43:41 2013 -0700 +++ b/make/project.properties Tue Mar 26 12:08:00 2013 -0700 @@ -210,7 +210,7 @@ # add '-Dtest.js.outofprocess' to run each test in a new sub-process run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -esa -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8 #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M -run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs} +run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main} run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy @@ -235,10 +235,12 @@ #naming of CC results #NB directory specified in the cc.dir will be cleaned up!!! cc.dir=${basedir}/../Codecoverage_Nashorn -cc.result.file.name=cc_nashorn.xml +cc.result.file.name=CC_${jcov}_nashorn.xml #dynamic CC parameters; please redefine in the ${user.home}/.nashorn.project.local.properties jcov2.lib.dir=${basedir}/../jcov2/lib jcov.jar=${jcov2.lib.dir}/jcov.jar cc.include=jdk\.nashorn\.* cc.exclude=jdk\.nashorn\.internal\.scripts\.* +cc.dynamic.genereate.template=true +cc.template=${cc.dir}/CC_template.xml cc.dynamic.args=-javaagent:${jcov.jar}=include=${cc.include},exclude=${cc.exclude},type=all,verbose=0,file=${cc.dir}/${cc.result.file.name} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/api/scripting/Formatter.java --- a/src/jdk/nashorn/api/scripting/Formatter.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/api/scripting/Formatter.java Tue Mar 26 12:08:00 2013 -0700 @@ -46,7 +46,7 @@ *

Pattern and the logic for parameter position: java.util.Formatter * */ -public final class Formatter { +final class Formatter { private Formatter() { } @@ -59,8 +59,8 @@ * @param args arguments referenced by the format specifiers in format * @return a formatted string */ - public static String format(final String format, final Object[] args) { - Matcher m = FS_PATTERN.matcher(format); + static String format(final String format, final Object[] args) { + final Matcher m = FS_PATTERN.matcher(format); int positionalParameter = 1; while (m.find()) { @@ -143,7 +143,7 @@ /** * Method to parse the integer of the argument index. * - * @param s + * @param s string to parse * @return -1 if parsing failed, 0 if string is null, > 0 integer */ private static int index(final String s) { @@ -166,7 +166,7 @@ * Method to check if a string contains '<'. This is used to find out if * previous parameter is used. * - * @param s + * @param s string to check * @return true if '<' is in the string, else false */ private static boolean isPreviousArgument(final String s) { diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/api/scripting/NashornScriptEngine.java --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Tue Mar 26 12:08:00 2013 -0700 @@ -32,6 +32,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.lang.reflect.Method; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; @@ -179,14 +180,14 @@ } private T getInterfaceInner(final Object self, final Class clazz) { - final Object realSelf; + final ScriptObject realSelf; final ScriptObject ctxtGlobal = getNashornGlobalFrom(context); if(self == null) { realSelf = ctxtGlobal; } else if (!(self instanceof ScriptObject)) { - realSelf = ScriptObjectMirror.unwrap(self, ctxtGlobal); + realSelf = (ScriptObject)ScriptObjectMirror.unwrap(self, ctxtGlobal); } else { - realSelf = self; + realSelf = (ScriptObject)self; } try { final ScriptObject oldGlobal = getNashornGlobal(); @@ -194,6 +195,10 @@ if(oldGlobal != ctxtGlobal) { setNashornGlobal(ctxtGlobal); } + + if (! isInterfaceImplemented(clazz, realSelf)) { + return null; + } return clazz.cast(JavaAdapterFactory.getConstructor(realSelf.getClass(), clazz).invoke(realSelf)); } finally { if(oldGlobal != ctxtGlobal) { @@ -394,14 +399,6 @@ setContextVariables(ctxt); final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); final String fileName = (val != null) ? val.toString() : ""; - - // NOTE: FIXME: If this is jrunscript's init.js, we want to run the replacement. - // This should go away once we fix jrunscript's copy of init.js. - if ("".equals(fileName)) { - evalSupportScript("resources/init.js", "nashorn:engine/resources/init.js"); - return null; - } - Object res = ScriptRuntime.apply(script, ctxtGlobal); return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(res, ctxtGlobal)); } catch (final Exception e) { @@ -471,6 +468,21 @@ } } + private static boolean isInterfaceImplemented(final Class iface, final ScriptObject sobj) { + for (final Method method : iface.getMethods()) { + // ignore methods of java.lang.Object class + if (method.getDeclaringClass() == Object.class) { + continue; + } + + Object obj = sobj.get(method.getName()); + if (! (obj instanceof ScriptFunction)) { + return false; + } + } + return true; + } + // don't make this public!! static ScriptObject getNashornGlobal() { return Context.getGlobal(); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java --- a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Tue Mar 26 12:08:00 2013 -0700 @@ -147,6 +147,7 @@ * @return newly created script engine. */ public ScriptEngine getScriptEngine(final ClassLoader appLoader) { + checkConfigPermission(); return new NashornScriptEngine(this, appLoader); } @@ -157,6 +158,7 @@ * @return newly created script engine. */ public ScriptEngine getScriptEngine(final String[] args) { + checkConfigPermission(); return new NashornScriptEngine(this, args, getAppClassLoader()); } @@ -168,11 +170,19 @@ * @return newly created script engine. */ public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader) { + checkConfigPermission(); return new NashornScriptEngine(this, args, appLoader); } // -- Internals only below this point + private static void checkConfigPermission() { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("nashorn.setConfig")); + } + } + private static final List names; private static final List mimeTypes; private static final List extensions; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/api/scripting/ScriptUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/api/scripting/ScriptUtils.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,60 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.api.scripting; + +import jdk.nashorn.internal.runtime.ScriptRuntime; + +/** + * Utilities that are to be called from script code + */ +public final class ScriptUtils { + private ScriptUtils() {} + + /** + * Returns AST as JSON compatible string. This is used to + * implement "parse" function in resources/parse.js script. + * + * @param code code to be parsed + * @param name name of the code source (used for location) + * @param includeLoc tells whether to include location information for nodes or not + * @return JSON string representation of AST of the supplied code + */ + public static String parse(final String code, final String name, final boolean includeLoc) { + return ScriptRuntime.parse(code, name, includeLoc); + } + + /** + * Method which converts javascript types to java types for the + * String.format method (jrunscript function sprintf). + * + * @param format a format string + * @param args arguments referenced by the format specifiers in format + * @return a formatted string + */ + public static String format(final String format, final Object[] args) { + return Formatter.format(format, args); + } +} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/api/scripting/resources/engine.js --- a/src/jdk/nashorn/api/scripting/resources/engine.js Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/api/scripting/resources/engine.js Tue Mar 26 12:08:00 2013 -0700 @@ -46,3 +46,49 @@ } writer.println(String(str)); } + +/** + * This is C-like printf + * + * @param format string to format the rest of the print items + * @param args variadic argument list + */ +Object.defineProperty(this, "printf", { + configurable: true, + enumerable: false, + writable: true, + value: function (format, args/*, more args*/) { + print(sprintf.apply(this, arguments)); + } +}); + +/** + * This is C-like sprintf + * + * @param format string to format the rest of the print items + * @param args variadic argument list + */ +Object.defineProperty(this, "sprintf", { + configurable: true, + enumerable: false, + writable: true, + value: function (format, args/*, more args*/) { + var len = arguments.length - 1; + var array = []; + + if (len < 0) { + return ""; + } + + for (var i = 0; i < len; i++) { + if (arguments[i+1] instanceof Date) { + array[i] = arguments[i+1].getTime(); + } else { + array[i] = arguments[i+1]; + } + } + + array = Java.toJavaArray(array); + return Packages.jdk.nashorn.api.scripting.ScriptUtils.format(format, array); + } +}); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/api/scripting/resources/init.js --- a/src/jdk/nashorn/api/scripting/resources/init.js Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,939 +0,0 @@ -/* - * Copyright (c) 2005, 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. 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. - */ - -/** - * jrunscript JavaScript built-in functions and objects. - */ - -/** - * Creates an object that delegates all method calls on - * it to the 'invoke' method on the given delegate object.
- * - * Example: - *

- * 
- *     var x  = { invoke: function(name, args) { //code...}
- *     var y = new JSInvoker(x);
- *     y.func(3, 3); // calls x.invoke('func', args); where args is array of arguments
- * 
- * 
- * @param obj object to be wrapped by JSInvoker - * @constructor - */ -function JSInvoker(obj) { - return new JSAdapter({ - __get__ : function(name) { - return function() { - return obj.invoke(name, arguments); - } - } - }); -} - -/** - * This variable represents OS environment. Environment - * variables can be accessed as fields of this object. For - * example, env.PATH will return PATH value configured. - */ -var env = new JSAdapter({ - __get__ : function (name) { - return java.lang.System.getenv(name); - }, - __has__ : function (name) { - return java.lang.System.getenv().containsKey(name); - }, - __getIds__ : function() { - return java.lang.System.getenv().keySet().toArray(); - }, - __delete__ : function(name) { - println("can't delete env item"); - }, - __put__ : function (name, value) { - println("can't change env item"); - }, - toString: function() { - return java.lang.System.getenv().toString(); - } -}); - -/** - * Creates a convenient script object to deal with java.util.Map instances. - * The result script object's field names are keys of the Map. For example, - * scriptObj.keyName can be used to access value associated with given key.
- * Example: - *
- * 
- *     var x = java.lang.SystemProperties();
- *     var y = jmap(x);
- *     println(y['java.class.path']); // prints java.class.path System property
- *     delete y['java.class.path']; // remove java.class.path System property
- * 
- * 
- * - * @param map java.util.Map instance that will be wrapped - * @constructor - */ -function jmap(map) { - return new JSAdapter({ - __get__ : function(name) { - if (map.containsKey(name)) { - return map.get(name); - } else { - return undefined; - } - }, - __has__ : function(name) { - return map.containsKey(name); - }, - - __delete__ : function (name) { - return map.remove(name); - }, - __put__ : function(name, value) { - map.put(name, value); - }, - __getIds__ : function() { - return map.keySet().toArray(); - }, - toString: function() { - return map.toString(); - } - }); -} - -/** - * Creates a convenient script object to deal with java.util.List instances. - * The result script object behaves like an array. For example, - * scriptObj[index] syntax can be used to access values in the List instance. - * 'length' field gives size of the List.
- * - * Example: - *
- * 
- *    var x = new java.util.ArrayList(4);
- *    x.add('Java');
- *    x.add('JavaScript');
- *    x.add('SQL');
- *    x.add('XML');
- *
- *    var y = jlist(x);
- *    println(y[2]); // prints third element of list
- *    println(y.length); // prints size of the list
- *
- * @param map java.util.List instance that will be wrapped
- * @constructor
- */
-function jlist(list) {
-    function isValid(index) {
-        return typeof(index) == 'number' &&
-            index > -1 && index < list.size();
-    }
-    return new JSAdapter({
-        __get__ :  function(name) {
-            if (isValid(name)) {
-                return list.get(name);
-            } else if (name == 'length') {
-                return list.size();
-            } else {
-                return undefined;
-            }
-        },
-        __has__ : function (name) {
-            return isValid(name) || name == 'length';
-        },
-        __delete__ : function(name) {
-            if (isValid(name)) {
-                list.remove(name);
-            }
-        },
-        __put__ : function(name, value) {
-            if (isValid(name)) {
-                list.set(name, value);
-            }
-        },
-        __getIds__: function() {
-            var res = new Array(list.size());
-            for (var i = 0; i < res.length; i++) {
-                res[i] = i;
-            }
-            return res;
-        },
-        toString: function() {
-            return list.toString();
-        }
-    });
-}
-
-/**
- * This is java.lang.System properties wrapped by JSAdapter.
- * For eg. to access java.class.path property, you can use
- * the syntax sysProps["java.class.path"]
- */
-var sysProps = new JSAdapter({
-    __get__ : function (name) {
-        return java.lang.System.getProperty(name);
-    },
-    __has__ : function (name) {
-        return java.lang.System.getProperty(name) != null;
-    },
-    __getIds__ : function() {
-        return java.lang.System.getProperties().keySet().toArray();
-    },
-    __delete__ : function(name) {
-        java.lang.System.clearProperty(name);
-        return true;
-    },
-    __put__ : function (name, value) {
-        java.lang.System.setProperty(name, value);
-    },
-    toString: function() {
-        return "";
-    }
-});
-
-// stdout, stderr & stdin
-var out = java.lang.System.out;
-var err = java.lang.System.err;
-// can't use 'in' because it is a JavaScript keyword :-(
-var inp = java.lang.System["in"];
-
-var BufferedInputStream = java.io.BufferedInputStream;
-var BufferedOutputStream = java.io.BufferedOutputStream;
-var BufferedReader = java.io.BufferedReader;
-var DataInputStream = java.io.DataInputStream;
-var File = java.io.File;
-var FileInputStream = java.io.FileInputStream;
-var FileOutputStream = java.io.FileOutputStream;
-var InputStream = java.io.InputStream;
-var InputStreamReader = java.io.InputStreamReader;
-var OutputStream = java.io.OutputStream;
-var Reader = java.io.Reader;
-var URL = java.net.URL;
-
-/**
- * Generic any object to input stream mapper
- * @param str input file name, URL or InputStream
- * @return InputStream object
- * @private
- */
-function inStream(str) {
-    if (typeof(str) == "string") {
-        // '-' means standard input
-        if (str == '-') {
-            return java.lang.System["in"];
-        }
-        // try file first
-        var file = null;
-        try {
-            file = pathToFile(str);
-        } catch (e) {
-        }
-        if (file && file.exists()) {
-            return new FileInputStream(file);
-        } else {
-            try {
-                // treat the string as URL
-                return new URL(str).openStream();
-            } catch (e) {
-                throw 'file or URL ' + str + ' not found';
-            }
-        }
-    } else {
-        if (str instanceof InputStream) {
-            return str;
-        } else if (str instanceof URL) {
-            return str.openStream();
-        } else if (str instanceof File) {
-            return new FileInputStream(str);
-        }
-    }
-    // everything failed, just give input stream
-    return java.lang.System["in"];
-}
-
-/**
- * Generic any object to output stream mapper
- *
- * @param out output file name or stream
- * @return OutputStream object
- * @private
- */
-function outStream(out) {
-    if (typeof(out) == "string") {
-        if (out == '>') {
-            return java.lang.System.out;
-        } else {
-            // treat it as file
-            return new FileOutputStream(pathToFile(out));
-        }
-    } else {
-        if (out instanceof OutputStream) {
-            return out;
-        } else if (out instanceof File) {
-            return new FileOutputStream(out);
-        }
-    }
-
-    // everything failed, just return System.out
-    return java.lang.System.out;
-}
-
-/**
- * stream close takes care not to close stdin, out & err.
- * @private
- */
-function streamClose(stream) {
-    if (stream) {
-        if (stream != java.lang.System["in"] &&
-            stream != java.lang.System.out &&
-            stream != java.lang.System.err) {
-            try {
-                stream.close();
-            } catch (e) {
-                println(e);
-            }
-        }
-    }
-}
-
-/**
- * Loads and evaluates JavaScript code from a stream or file or URL
- * - * Examples: - *
- * 
- *    load('test.js'); // load script file 'test.js'
- *    load('http://java.sun.com/foo.js'); // load from a URL
- * 
- * 
- * - * @param str input from which script is loaded and evaluated - */ -if (typeof(load) == 'undefined') { - var load = function(str) { - var stream = inStream(str); - var bstream = new BufferedInputStream(stream); - var reader = new BufferedReader(new InputStreamReader(bstream)); - var oldFilename = engine.get(engine.FILENAME); - engine.put(engine.FILENAME, str); - try { - engine.eval(reader); - } finally { - engine.put(engine.FILENAME, oldFilename); - streamClose(stream); - } - } -} - -// file system utilities - -/** - * Creates a Java byte[] of given length - * @param len size of the array to create - * @private - */ -function javaByteArray(len) { - return java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, len); -} - -var curDir = new File('.'); - -/** - * Print present working directory - */ -function pwd() { - println(curDir.getAbsolutePath()); -} - -/** - * Changes present working directory to given directory - * @param target directory to change to. optional, defaults to user's HOME - */ -function cd(target) { - if (target == undefined) { - target = sysProps["user.home"]; - } - if (!(target instanceof File)) { - target = pathToFile(target); - } - if (target.exists() && target.isDirectory()) { - curDir = target; - } else { - println(target + " is not a directory"); - } -} - -/** - * Converts path to java.io.File taking care of shell present working dir - * - * @param pathname file path to be converted - * @private - */ -function pathToFile(pathname) { - var tmp = pathname; - if (!(tmp instanceof File)) { - tmp = new File(tmp); - } - if (!tmp.isAbsolute()) { - return new File(curDir, pathname); - } else { - return tmp; - } -} - -/** - * Copies a file or URL or stream to another file or stream - * - * @param from input file or URL or stream - * @param to output stream or file - */ -function cp(from, to) { - if (from == to) { - println("file " + from + " cannot be copied onto itself!"); - return; - } - var inp = inStream(from); - var out = outStream(to); - var binp = new BufferedInputStream(inp); - var bout = new BufferedOutputStream(out); - var buff = javaByteArray(1024); - var len; - while ((len = binp.read(buff)) > 0 ) - bout.write(buff, 0, len); - - bout.flush(); - streamClose(inp); - streamClose(out); -} - -/** - * Shows the content of a file or URL or any InputStream
- * Examples: - *
- * 
- *    cat('test.txt'); // show test.txt file contents
- *    cat('http://java.net'); // show the contents from the URL http://java.net
- * 
- * 
- * @param obj input to show - * @param pattern optional. show only the lines matching the pattern - */ -function cat(obj, pattern) { - if (obj instanceof File && obj.isDirectory()) { - ls(obj); - return; - } - - var inp = null; - if (!(obj instanceof Reader)) { - inp = inStream(obj); - obj = new BufferedReader(new InputStreamReader(inp)); - } - var line; - if (pattern) { - var count = 1; - while ((line=obj.readLine()) != null) { - if (line.match(pattern)) { - println(count + "\t: " + line); - } - count++; - } - } else { - while ((line=obj.readLine()) != null) { - println(line); - } - } -} - -/** - * Returns directory part of a filename - * - * @param pathname input path name - * @return directory part of the given file name - */ -function dirname(pathname) { - var dirName = "."; - // Normalize '/' to local file separator before work. - var i = pathname.replace('/', File.separatorChar ).lastIndexOf( - File.separator ); - if ( i != -1 ) - dirName = pathname.substring(0, i); - return dirName; -} - -/** - * Creates a new dir of given name - * - * @param dir name of the new directory - */ -function mkdir(dir) { - dir = pathToFile(dir); - println(dir.mkdir()? "created" : "can not create dir"); -} - -/** - * Creates the directory named by given pathname, including - * any necessary but nonexistent parent directories. - * - * @param dir input path name - */ -function mkdirs(dir) { - dir = pathToFile(dir); - println(dir.mkdirs()? "created" : "can not create dirs"); -} - -/** - * Removes a given file - * - * @param pathname name of the file - */ -function rm(pathname) { - var file = pathToFile(pathname); - if (!file.exists()) { - println("file not found: " + pathname); - return false; - } - // note that delete is a keyword in JavaScript! - println(file["delete"]()? "deleted" : "can not delete"); -} - -/** - * Removes a given directory - * - * @param pathname name of the directory - */ -function rmdir(pathname) { - rm(pathname); -} - -/** - * Synonym for 'rm' - */ -function del(pathname) { - rm(pathname); -} - -/** - * Moves a file to another - * - * @param from original name of the file - * @param to new name for the file - */ -function mv(from, to) { - println(pathToFile(from).renameTo(pathToFile(to))? - "moved" : "can not move"); -} - -/** - * Synonym for 'mv'. - */ -function ren(from, to) { - mv(from, to); -} - -var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; - -/** - * Helper function called by ls - * @private - */ -function printFile(f) { - var sb = new java.lang.StringBuffer(); - sb.append(f.isDirectory()? "d" : "-"); - sb.append(f.canRead() ? "r": "-" ); - sb.append(f.canWrite() ? "w": "-" ); - sb.append(" "); - - var d = new java.util.Date(f.lastModified()); - var c = new java.util.GregorianCalendar(); - c.setTime(d); - var day = c.get(java.util.Calendar.DAY_OF_MONTH); - sb.append(months[c.get(java.util.Calendar.MONTH)] - + " " + day ); - if (day < 10) { - sb.append(" "); - } - - // to get fixed length 'length' field - var fieldlen = 8; - var len = new java.lang.StringBuffer(); - for(var j=0; j - * - * Examples: - *
- * 
- *    find('.')
- *    find('.', '.*\.class', rm);  // remove all .class files
- *    find('.', '.*\.java');       // print fullpath of each .java file
- *    find('.', '.*\.java', cat);  // print all .java files
- * 
- * 
- * - * @param dir directory to search files - * @param pattern to search in the files - * @param callback function to call for matching files - */ -function find(dir, pattern, callback) { - dir = pathToFile(dir); - if (!callback) callback = print; - var files = dir.listFiles(); - for (var f in files) { - var file = files[f]; - if (file.isDirectory()) { - find(file, pattern, callback); - } else { - if (pattern) { - if (file.getName().match(pattern)) { - callback(file); - } - } else { - callback(file); - } - } - } -} - -// process utilities - -/** - * Exec's a child process, waits for completion & returns exit code - * - * @param cmd command to execute in child process - */ -function exec(cmd) { - var process = java.lang.Runtime.getRuntime().exec(cmd); - var inp = new DataInputStream(process.getInputStream()); - var line = null; - while ((line = inp.readLine()) != null) { - println(line); - } - process.waitFor(); - $exit = process.exitValue(); -} - -// XML utilities - -/** - * Converts input to DOM Document object - * - * @param inp file or reader. optional, without this param, - * this function returns a new DOM Document. - * @return returns a DOM Document object - */ -function XMLDocument(inp) { - var factory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); - var builder = factory.newDocumentBuilder(); - if (inp) { - if (typeof(inp) == "string") { - return builder.parse(pathToFile(inp)); - } else { - return builder.parse(inp); - } - } else { - return builder.newDocument(); - } -} - -/** - * Converts arbitrary stream, file, URL to XMLSource - * - * @param inp input stream or file or URL - * @return XMLSource object - */ -function XMLSource(inp) { - if (inp instanceof javax.xml.transform.Source) { - return inp; - } else if (inp instanceof Packages.org.w3c.dom.Document) { - return new javax.xml.transform.dom.DOMSource(inp); - } else { - inp = new BufferedInputStream(inStream(inp)); - return new javax.xml.transform.stream.StreamSource(inp); - } -} - -/** - * Converts arbitrary stream, file to XMLResult - * - * @param inp output stream or file - * @return XMLResult object - */ -function XMLResult(out) { - if (out instanceof javax.xml.transform.Result) { - return out; - } else if (out instanceof Packages.org.w3c.dom.Document) { - return new javax.xml.transform.dom.DOMResult(out); - } else { - out = new BufferedOutputStream(outStream(out)); - return new javax.xml.transform.stream.StreamResult(out); - } -} - -/** - * Perform XSLT transform - * - * @param inp Input XML to transform (URL, File or InputStream) - * @param style XSL Stylesheet to be used (URL, File or InputStream). optional. - * @param out Output XML (File or OutputStream - */ -function XSLTransform(inp, style, out) { - switch (arguments.length) { - case 2: - inp = arguments[0]; - out = arguments[1]; - break; - case 3: - inp = arguments[0]; - style = arguments[1]; - out = arguments[2]; - break; - default: - println("XSL tranform requires 2 or 3 arguments"); - return; - } - - var factory = javax.xml.transform.TransformerFactory.newInstance(); - var transformer; - if (style) { - transformer = factory.newTransformer(XMLSource(style)); - } else { - transformer = factory.newTransformer(); - } - var source = XMLSource(inp); - var result = XMLResult(out); - transformer.transform(source, result); - if (source.getInputStream) { - streamClose(source.getInputStream()); - } - if (result.getOutputStream) { - streamClose(result.getOutputStream()); - } -} - -// miscellaneous utilities - -/** - * Prints which command is selected from PATH - * - * @param cmd name of the command searched from PATH - */ -function which(cmd) { - var st = new java.util.StringTokenizer(env.PATH, File.pathSeparator); - while (st.hasMoreTokens()) { - var file = new File(st.nextToken(), cmd); - if (file.exists()) { - println(file.getAbsolutePath()); - return; - } - } -} - -/** - * Prints IP addresses of given domain name - * - * @param name domain name - */ -function ip(name) { - var addrs = InetAddress.getAllByName(name); - for (var i in addrs) { - println(addrs[i]); - } -} - -/** - * Prints current date in current locale - */ -function date() { - println(new Date().toLocaleString()); -} - -/** - * Echoes the given string arguments - */ -function echo(x) { - for (var i = 0; i < arguments.length; i++) { - println(arguments[i]); - } -} - -/** - * Reads one or more lines from stdin after printing prompt - * - * @param prompt optional, default is '>' - * @param multiline to tell whether to read single line or multiple lines - */ -function read(prompt, multiline) { - if (!prompt) { - prompt = '>'; - } - var inp = java.lang.System["in"]; - var reader = new BufferedReader(new InputStreamReader(inp)); - if (multiline) { - var line = ''; - while (true) { - java.lang.System.err.print(prompt); - java.lang.System.err.flush(); - var tmp = reader.readLine(); - if (tmp == '' || tmp == null) break; - line += tmp + '\n'; - } - return line; - } else { - java.lang.System.err.print(prompt); - java.lang.System.err.flush(); - return reader.readLine(); - } -} - -if (typeof(println) == 'undefined') { - var print = function(str, newline) { - if (typeof(str) == 'undefined') { - str = 'undefined'; - } else if (str == null) { - str = 'null'; - } - - if (!(out instanceof java.io.PrintWriter)) { - out = new java.io.PrintWriter(out); - } - - out.print(String(str)); - if (newline) { - out.print('\n'); - } - out.flush(); - } - - var println = function(str) { - print(str, true); - }; -} - -/** - * This is C-like printf - * - * @param format string to format the rest of the print items - * @param args variadic argument list - */ -function printf(format, args/*, more args*/) { - print(sprintf.apply(this, arguments)); -} - -/** - * This is C-like sprintf - * - * @param format string to format the rest of the print items - * @param args variadic argument list - */ -function sprintf(format, args/*, more args*/) { - var len = arguments.length - 1; - var array = []; - - if (len < 0) { - return ""; - } - - for (var i = 0; i < len; i++) { - if (arguments[i+1] instanceof Date) { - array[i] = arguments[i+1].getTime(); - } else { - array[i] = arguments[i+1]; - } - } - - array = Java.toJavaArray(array); - return Packages.jdk.nashorn.api.scripting.Formatter.format(format, array); -} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/Attr.java --- a/src/jdk/nashorn/internal/codegen/Attr.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/Attr.java Tue Mar 26 12:08:00 2013 -0700 @@ -37,13 +37,16 @@ import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; import static jdk.nashorn.internal.ir.Symbol.IS_LET; import static jdk.nashorn.internal.ir.Symbol.IS_PARAM; +import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE; import static jdk.nashorn.internal.ir.Symbol.IS_THIS; import static jdk.nashorn.internal.ir.Symbol.IS_VAR; +import static jdk.nashorn.internal.ir.Symbol.KINDMASK; import java.util.ArrayList; import java.util.HashSet; -import java.util.LinkedList; +import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import java.util.Set; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; @@ -55,14 +58,15 @@ import jdk.nashorn.internal.ir.CatchNode; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IndexNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ObjectNode; import jdk.nashorn.internal.ir.PropertyNode; -import jdk.nashorn.internal.ir.ReferenceNode; import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.RuntimeNode.Request; @@ -115,6 +119,8 @@ */ private Set localUses; + private final LexicalContext lexicalContext = new LexicalContext(); + private static final DebugLogger LOG = new DebugLogger("attr"); private static final boolean DEBUG = LOG.isEnabled(); @@ -135,14 +141,15 @@ } @Override - public Node leave(final AccessNode accessNode) { + public Node leaveAccessNode(final AccessNode accessNode) { newTemporary(Type.OBJECT, accessNode); //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this end(accessNode); return accessNode; } @Override - public Node enter(final Block block) { + public Node enterBlock(final Block block) { + lexicalContext.push(block); start(block); final Set savedLocalDefs = localDefs; @@ -158,9 +165,7 @@ localDefs = new HashSet<>(savedLocalDefs); localUses = new HashSet<>(savedLocalUses); - for (final Node statement : block.getStatements()) { - statement.accept(this); - } + block.visitStatements(this); } finally { localDefs = savedLocalDefs; localUses = savedLocalUses; @@ -170,11 +175,12 @@ end(block); + lexicalContext.pop(block); return null; } @Override - public Node enter(final CallNode callNode) { + public Node enterCallNode(final CallNode callNode) { start(callNode); callNode.getFunction().accept(this); @@ -195,8 +201,7 @@ evalArgs.setThis(thisNode); } - newTemporary(Type.OBJECT, callNode); // object type here, access specialization in FinalizeTypes may narrow it later - newType(callNode.getFunction().getSymbol(), Type.OBJECT); + newTemporary(callNode.getType(), callNode); // access specialization in FinalizeTypes may narrow it further later end(callNode); @@ -204,29 +209,106 @@ } @Override - public Node enter(final CatchNode catchNode) { + public Node enterCatchNode(final CatchNode catchNode) { final IdentNode exception = catchNode.getException(); final Block block = getCurrentBlock(); start(catchNode); // define block-local exception variable - final Symbol def = block.defineSymbol(exception.getName(), IS_VAR | IS_LET, exception); + final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception); newType(def, Type.OBJECT); addLocalDef(exception.getName()); return catchNode; } + /** + * Declare the definition of a new symbol. + * + * @param name Name of symbol. + * @param symbolFlags Symbol flags. + * @param node Defining Node. + * + * @return Symbol for given name or null for redefinition. + */ + private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) { + int flags = symbolFlags; + Symbol symbol = findSymbol(block, name); // Locate symbol. + + if ((flags & KINDMASK) == IS_GLOBAL) { + flags |= IS_SCOPE; + } + + final FunctionNode function = lexicalContext.getFunction(block); + if (symbol != null) { + // Symbol was already defined. Check if it needs to be redefined. + if ((flags & KINDMASK) == IS_PARAM) { + if (!isLocal(function, symbol)) { + // Not defined in this function. Create a new definition. + symbol = null; + } else if (symbol.isParam()) { + // Duplicate parameter. Null return will force an error. + assert false : "duplicate parameter"; + return null; + } + } else if ((flags & KINDMASK) == IS_VAR) { + if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) { + assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == block) : "duplicate let variable in block"; + // Always create a new definition. + symbol = null; + } else { + // Not defined in this function. Create a new definition. + if (!isLocal(function, symbol) || symbol.less(IS_VAR)) { + symbol = null; + } + } + } + } + + if (symbol == null) { + // If not found, then create a new one. + Block symbolBlock; + + // Determine where to create it. + if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) { + symbolBlock = block; + } else { + symbolBlock = function; + } + + // Create and add to appropriate block. + symbol = new Symbol(name, flags, node, symbolBlock); + symbolBlock.putSymbol(name, symbol); + + if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { + symbolBlock.getFrame().addSymbol(symbol); + symbol.setNeedsSlot(true); + } + } else if (symbol.less(flags)) { + symbol.setFlags(flags); + } + + if (node != null) { + node.setSymbol(symbol); + } + + return symbol; + } + @Override - public Node enter(final FunctionNode functionNode) { + public Node enterFunctionNode(final FunctionNode functionNode) { start(functionNode, false); if (functionNode.isLazy()) { - LOG.info("LAZY: " + functionNode.getName()); + LOG.info("LAZY: " + functionNode.getName() + " => Promoting to OBJECT"); + newTemporary(lexicalContext.getCurrentFunction(), Type.OBJECT, functionNode); + functionNode.setReturnType(Type.OBJECT); end(functionNode); return null; } + lexicalContext.push(functionNode); + clearLocalDefs(); clearLocalUses(); @@ -242,24 +324,36 @@ initScope(functionNode); initReturn(functionNode); - // Add all nested functions as symbols in this function - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { + // Add all nested declared functions as symbols in this function + for (final FunctionNode nestedFunction : functionNode.getDeclaredFunctions()) { final IdentNode ident = nestedFunction.getIdent(); - if (ident != null && nestedFunction.isStatement()) { - final Symbol functionSymbol = functionNode.defineSymbol(ident.getName(), IS_VAR, nestedFunction); + if (ident != null) { + assert nestedFunction.isDeclared(); + final Symbol functionSymbol = defineSymbol(functionNode, ident.getName(), IS_VAR, nestedFunction); newType(functionSymbol, Type.typeFor(ScriptFunction.class)); } } - if (functionNode.isScript()) { + if (functionNode.isProgram()) { initFromPropertyMap(functionNode); } // Add function name as local symbol - if (!functionNode.isStatement() && !functionNode.isAnonymous() && !functionNode.isScript()) { - final Symbol selfSymbol = functionNode.defineSymbol(functionNode.getIdent().getName(), IS_VAR, functionNode); - newType(selfSymbol, Type.OBJECT); - selfSymbol.setNode(functionNode); + if (!functionNode.isDeclared() && !functionNode.isProgram()) { + if(functionNode.getSymbol() != null) { + // a temporary left over from an earlier pass when the function was lazy + assert functionNode.getSymbol().isTemp(); + // remove it + functionNode.setSymbol(null); + } + final Symbol selfSymbol; + if(functionNode.isAnonymous()) { + selfSymbol = newTemporary(functionNode, Type.OBJECT, functionNode); + } else { + selfSymbol = defineSymbol(functionNode, functionNode.getIdent().getName(), IS_VAR, functionNode); + newType(selfSymbol, Type.OBJECT); + selfSymbol.setNode(functionNode); + } } /* @@ -280,32 +374,26 @@ */ final List declaredSymbols = new ArrayList<>(); - for (final VarNode decl : functionNode.getDeclarations()) { - final IdentNode ident = decl.getName(); - // any declared symbols that aren't visited need to be typed as well, hence the list - declaredSymbols.add(functionNode.defineSymbol(ident.getName(), IS_VAR, new IdentNode(ident))); - } - - // Every nested function needs a definition in the outer function with its name. Add these. - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { - final VarNode varNode = nestedFunction.getFunctionVarNode(); - if (varNode != null) { - varNode.accept(this); - assert varNode.isFunctionVarNode() : varNode + " should be function var node"; + // This visitor will assign symbol to all declared variables, except function declarations (which are taken care + // in a separate step above) and "var" declarations in for loop initializers. + functionNode.accept(new NodeOperatorVisitor() { + @Override + public Node enterFunctionNode(FunctionNode nestedFn) { + // Don't descend into nested functions + return nestedFn == functionNode ? nestedFn : null; } - } - - for (final Node statement : functionNode.getStatements()) { - if (statement instanceof VarNode && ((VarNode)statement).isFunctionVarNode()) { - continue; //var nodes have already been processed, skip or they will generate additional defs/uses and false "can be undefined" + @Override + public Node enterVarNode(VarNode varNode) { + if(varNode.isStatement() && !varNode.isFunctionDeclaration()) { + final IdentNode ident = varNode.getName(); + // any declared symbols that aren't visited need to be typed as well, hence the list + declaredSymbols.add(defineSymbol(functionNode, ident.getName(), IS_VAR, new IdentNode(ident))); + } + return null; } - statement.accept(this); - } + }); - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { - LOG.info("Going into nested function " + functionNode.getName() + " -> " + nestedFunction.getName()); - nestedFunction.accept(this); - } + visitFunctionStatements(functionNode); //unknown parameters are promoted to object type. finalizeParameters(functionNode); @@ -332,13 +420,28 @@ functionNode.setNeedsSelfSymbol(functionNode.getSelfSymbolInit().accept(this)); } + if (functionNode.hasLazyChildren()) { + objectifySymbols(functionNode); + } + functionNode.popFrame(); + functionNode.setState(CompilationState.ATTR); + end(functionNode, false); + lexicalContext.pop(functionNode); return null; } + private void visitFunctionStatements(final FunctionNode functionNode) { + final List newStatements = new ArrayList<>(functionNode.getStatements()); + for(ListIterator stmts = newStatements.listIterator(); stmts.hasNext();) { + stmts.set(stmts.next().accept(this)); + } + functionNode.setStatements(newStatements); + } + @Override public Node leaveCONVERT(final UnaryNode unaryNode) { assert false : "There should be no convert operators in IR during Attribution"; @@ -347,7 +450,7 @@ } @Override - public Node enter(final IdentNode identNode) { + public Node enterIdentNode(final IdentNode identNode) { final String name = identNode.getName(); start(identNode); @@ -364,7 +467,7 @@ final Block block = getCurrentBlock(); final Symbol oldSymbol = identNode.getSymbol(); - Symbol symbol = block.findSymbol(name); + Symbol symbol = findSymbol(block, name); //If an existing symbol with the name is found, use that otherwise, declare a new one if (symbol != null) { @@ -388,22 +491,13 @@ } identNode.setSymbol(symbol); - if (!getCurrentFunctionNode().isLocal(symbol)) { - // non-local: we need to put symbol in scope (if it isn't already) - if (!symbol.isScope()) { - final List lookupBlocks = findLookupBlocksHelper(getCurrentFunctionNode(), symbol.findFunction()); - for (final Block lookupBlock : lookupBlocks) { - final Symbol refSymbol = lookupBlock.findSymbol(name); - if (refSymbol != null) { // See NASHORN-837, function declaration in lexical scope: try {} catch (x){ function f() { use(x) } } f() - LOG.finest("Found a ref symbol that must be scope " + refSymbol); - refSymbol.setIsScope(); - } - } - } + // non-local: we need to put symbol in scope (if it isn't already) + if (!isLocal(getCurrentFunctionNode(), symbol) && !symbol.isScope()) { + symbol.setIsScope(); } } else { LOG.info("No symbol exists. Declare undefined: " + symbol); - symbol = block.useSymbol(name, identNode); + symbol = useSymbol(block, name, identNode); // we have never seen this before, it can be undefined newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway? symbol.setCanBeUndefined(); @@ -412,9 +506,10 @@ assert symbol != null; if(symbol.isGlobal()) { - getCurrentFunctionNode().setUsesGlobalSymbol(); + setUsesGlobalSymbol(); } else if(symbol.isScope()) { - getCurrentFunctionNode().setUsesScopeSymbol(symbol); + final Iterator blocks = lexicalContext.getBlocks(); + blocks.next().setUsesScopeSymbol(symbol, blocks); } if (symbol != oldSymbol && !identNode.isInitializedHere()) { @@ -427,15 +522,68 @@ return null; } + /** + * Marks the current function as one using any global symbol. The function and all its parent functions will all be + * marked as needing parent scope. + * @see #needsParentScope() + */ + private void setUsesGlobalSymbol() { + for(final Iterator fns = lexicalContext.getFunctions(); fns.hasNext();) { + fns.next().setUsesAncestorScope(); + } + } + + /** + * Declare the use of a symbol in a block. + * + * @param block block in which the symbol is used + * @param name Name of symbol. + * @param node Using node + * + * @return Symbol for given name. + */ + private Symbol useSymbol(final Block block, final String name, final Node node) { + Symbol symbol = findSymbol(block, name); + + if (symbol == null) { + // If not found, declare as a free var. + symbol = defineSymbol(block, name, IS_GLOBAL, node); + } else { + node.setSymbol(symbol); + } + + return symbol; + } + + + /** + * Search for symbol in the lexical context starting from the given block. + * @param name Symbol name. + * @return Found symbol or null if not found. + */ + private Symbol findSymbol(final Block block, final String name) { + // Search up block chain to locate symbol. + + for(final Iterator blocks = lexicalContext.getBlocks(block); blocks.hasNext();) { + // Find name. + final Symbol symbol = blocks.next().getExistingSymbol(name); + // If found then we are good. + if(symbol != null) { + return symbol; + } + } + return null; + } + @Override - public Node leave(final IndexNode indexNode) { - newTemporary(Type.OBJECT, indexNode); //TORO + public Node leaveIndexNode(final IndexNode indexNode) { + newTemporary(Type.OBJECT, indexNode); //TODO return indexNode; } @SuppressWarnings("rawtypes") @Override - public Node enter(final LiteralNode literalNode) { + public Node enterLiteralNode(final LiteralNode literalNode) { try { start(literalNode); assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens @@ -464,14 +612,14 @@ } @Override - public Node leave(final ObjectNode objectNode) { + public Node leaveObjectNode(final ObjectNode objectNode) { newTemporary(Type.OBJECT, objectNode); end(objectNode); return objectNode; } @Override - public Node enter(final PropertyNode propertyNode) { + public Node enterPropertyNode(final PropertyNode propertyNode) { // assign a pseudo symbol to property name, see NASHORN-710 propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); end(propertyNode); @@ -479,31 +627,7 @@ } @Override - public Node enter(final ReferenceNode referenceNode) { - final FunctionNode functionNode = referenceNode.getReference(); - if (functionNode != null) { - functionNode.addReferencingParentBlock(getCurrentBlock()); - } - return referenceNode; - } - - @Override - public Node leave(final ReferenceNode referenceNode) { - newTemporary(Type.OBJECT, referenceNode); //reference node type is always an object, i.e. the scriptFunction. the function return type varies though - - final FunctionNode functionNode = referenceNode.getReference(); - //assert !functionNode.getType().isUnknown() || functionNode.isLazy() : functionNode.getType(); - if (functionNode.isLazy()) { - LOG.info("Lazy function node call reference: " + functionNode.getName() + " => Promoting to OBJECT"); - functionNode.setReturnType(Type.OBJECT); - } - end(referenceNode); - - return referenceNode; - } - - @Override - public Node leave(final ReturnNode returnNode) { + public Node leaveReturnNode(final ReturnNode returnNode) { final Node expr = returnNode.getExpression(); if (expr != null) { @@ -522,7 +646,7 @@ } @Override - public Node leave(final SwitchNode switchNode) { + public Node leaveSwitchNode(final SwitchNode switchNode) { Type type = Type.UNKNOWN; for (final CaseNode caseNode : switchNode.getCases()) { @@ -559,7 +683,7 @@ } @Override - public Node leave(final TryNode tryNode) { + public Node leaveTryNode(final TryNode tryNode) { tryNode.setException(exceptionSymbol()); if (tryNode.getFinallyBody() != null) { @@ -572,13 +696,13 @@ } @Override - public Node enter(final VarNode varNode) { + public Node enterVarNode(final VarNode varNode) { start(varNode); final IdentNode ident = varNode.getName(); final String name = ident.getName(); - final Symbol symbol = getCurrentBlock().defineSymbol(name, IS_VAR, ident); + final Symbol symbol = defineSymbol(getCurrentBlock(), name, IS_VAR, ident); assert symbol != null; LOG.info("VarNode " + varNode + " set symbol " + symbol); @@ -590,23 +714,15 @@ symbol.setCanBeUndefined(); } - if (varNode.getInit() != null) { - varNode.getInit().accept(this); - } - return varNode; } @Override - public Node leave(final VarNode varNode) { + public Node leaveVarNode(final VarNode varNode) { final Node init = varNode.getInit(); final IdentNode ident = varNode.getName(); final String name = ident.getName(); - if (init != null) { - addLocalDef(name); - } - if (init == null) { // var x; with no init will be treated like a use of x by // visit(IdentNode) unless we remove the name @@ -615,8 +731,10 @@ return varNode; } + addLocalDef(name); + final Symbol symbol = varNode.getSymbol(); - final boolean isScript = symbol.getBlock().getFunction().isScript(); //see NASHORN-56 + final boolean isScript = lexicalContext.getFunction(symbol.getBlock()).isProgram(); //see NASHORN-56 if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) { // Forbid integers as local vars for now as we have no way to treat them as undefined newType(symbol, init.getType()); @@ -710,11 +828,9 @@ runtimeNode = new RuntimeNode(unaryNode, request, args); assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //clone constructor should do this - runtimeNode.accept(this); - return runtimeNode; + return leaveRuntimeNode(runtimeNode); } - @Override public Node leaveNEW(final UnaryNode unaryNode) { newTemporary(Type.OBJECT, unaryNode); @@ -747,7 +863,7 @@ runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args); assert runtimeNode.getSymbol() == unaryNode.getSymbol(); - runtimeNode.accept(this); + runtimeNode = (RuntimeNode)leaveRuntimeNode(runtimeNode); end(unaryNode); @@ -755,7 +871,7 @@ } @Override - public Node leave(final RuntimeNode runtimeNode) { + public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { newTemporary(runtimeNode.getRequest().getReturnType(), runtimeNode); return runtimeNode; } @@ -815,12 +931,12 @@ final IdentNode ident = (IdentNode)lhs; final String name = ident.getName(); - Symbol symbol = getCurrentBlock().findSymbol(name); + Symbol symbol = findSymbol(getCurrentBlock(), name); if (symbol == null) { - symbol = block.defineSymbol(name, IS_GLOBAL, ident); + symbol = defineSymbol(block, name, IS_GLOBAL, ident); binaryNode.setSymbol(symbol); - } else if (!getCurrentFunctionNode().isLocal(symbol)) { + } else if (!isLocal(getCurrentFunctionNode(), symbol)) { symbol.setIsScope(); } @@ -830,6 +946,12 @@ return binaryNode; } + private boolean isLocal(FunctionNode function, Symbol symbol) { + final Block block = symbol.getBlock(); + // some temp symbols have no block, so can be assumed local + return block == null || lexicalContext.getFunction(block) == function; + } + @Override public Node enterASSIGN(final BinaryNode binaryNode) { return enterAssignmentNode(binaryNode); @@ -957,20 +1079,17 @@ @Override public Node leaveBIT_AND(final BinaryNode binaryNode) { - newTemporary(Type.INT, binaryNode); - return binaryNode; + return end(coerce(binaryNode, Type.INT)); } @Override public Node leaveBIT_OR(final BinaryNode binaryNode) { - newTemporary(Type.INT, binaryNode); - return binaryNode; + return end(coerce(binaryNode, Type.INT)); } @Override public Node leaveBIT_XOR(final BinaryNode binaryNode) { - newTemporary(Type.INT, binaryNode); - return binaryNode; + return end(coerce(binaryNode, Type.INT)); } @Override @@ -990,7 +1109,7 @@ return leaveBinaryArithmetic(binaryNode); } - private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) { + private Node leaveCmp(final BinaryNode binaryNode) { final Node lhs = binaryNode.lhs(); final Node rhs = binaryNode.rhs(); @@ -1002,49 +1121,64 @@ return binaryNode; } + private Node coerce(final BinaryNode binaryNode, final Type operandType, final Type destType) { + // TODO we currently don't support changing inferred type based on uses, only on + // definitions. we would need some additional logic. We probably want to do that + // in the future, if e.g. a specialized method gets parameter that is only used + // as, say, an int : function(x) { return x & 4711 }, and x is not defined in + // the function. to make this work, uncomment the following two type inferences + // and debug. + + //newType(binaryNode.lhs().getSymbol(), operandType); + //newType(binaryNode.rhs().getSymbol(), operandType); + newTemporary(destType, binaryNode); + return binaryNode; + } + + private Node coerce(final BinaryNode binaryNode, final Type type) { + return coerce(binaryNode, type, type); + } + //leave a binary node and inherit the widest type of lhs , rhs private Node leaveBinaryArithmetic(final BinaryNode binaryNode) { - if (!Compiler.shouldUseIntegerArithmetic()) { - newTemporary(Type.NUMBER, binaryNode); - return binaryNode; - } - newTemporary(Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType(), Type.NUMBER), binaryNode); - return binaryNode; + assert !Compiler.shouldUseIntegerArithmetic(); + return end(coerce(binaryNode, Type.NUMBER)); } @Override public Node leaveEQ(final BinaryNode binaryNode) { - return leaveCmp(binaryNode, Request.EQ); + return leaveCmp(binaryNode); } @Override public Node leaveEQ_STRICT(final BinaryNode binaryNode) { - return leaveCmp(binaryNode, Request.EQ_STRICT); + return leaveCmp(binaryNode); } @Override public Node leaveGE(final BinaryNode binaryNode) { - return leaveCmp(binaryNode, Request.GE); + return leaveCmp(binaryNode); } @Override public Node leaveGT(final BinaryNode binaryNode) { - return leaveCmp(binaryNode, Request.GT); + return leaveCmp(binaryNode); } @Override public Node leaveIN(final BinaryNode binaryNode) { - try { - return new RuntimeNode(binaryNode, Request.IN).accept(this); - } finally { - end(binaryNode); - } + return leaveBinaryRuntimeOperator(binaryNode, Request.IN); } @Override public Node leaveINSTANCEOF(final BinaryNode binaryNode) { + return leaveBinaryRuntimeOperator(binaryNode, Request.INSTANCEOF); + } + + private Node leaveBinaryRuntimeOperator(final BinaryNode binaryNode, final Request request) { try { - return new RuntimeNode(binaryNode, Request.INSTANCEOF).accept(this); + // Don't do a full RuntimeNode.accept, as we don't want to double-visit the binary node operands + return leaveRuntimeNode(new RuntimeNode(binaryNode, request)); } finally { end(binaryNode); } @@ -1052,12 +1186,12 @@ @Override public Node leaveLE(final BinaryNode binaryNode) { - return leaveCmp(binaryNode, Request.LE); + return leaveCmp(binaryNode); } @Override public Node leaveLT(final BinaryNode binaryNode) { - return leaveCmp(binaryNode, Request.LT); + return leaveCmp(binaryNode); } @Override @@ -1072,12 +1206,12 @@ @Override public Node leaveNE(final BinaryNode binaryNode) { - return leaveCmp(binaryNode, Request.NE); + return leaveCmp(binaryNode); } @Override public Node leaveNE_STRICT(final BinaryNode binaryNode) { - return leaveCmp(binaryNode, Request.NE_STRICT); + return leaveCmp(binaryNode); } @Override @@ -1089,23 +1223,17 @@ @Override public Node leaveSAR(final BinaryNode binaryNode) { - newTemporary(Type.INT, binaryNode); - end(binaryNode); - return binaryNode; + return end(coerce(binaryNode, Type.INT)); } @Override public Node leaveSHL(final BinaryNode binaryNode) { - newTemporary(Type.INT, binaryNode); - end(binaryNode); - return binaryNode; + return end(coerce(binaryNode, Type.INT)); } @Override public Node leaveSHR(final BinaryNode binaryNode) { - newTemporary(Type.LONG, binaryNode); - end(binaryNode); - return binaryNode; + return end(coerce(binaryNode, Type.LONG)); } @Override @@ -1114,9 +1242,9 @@ } @Override - public Node leave(final ForNode forNode) { + public Node leaveForNode(final ForNode forNode) { if (forNode.isForIn()) { - forNode.setIterator(newInternal(getCurrentFunctionNode(), getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73 + forNode.setIterator(newInternal(getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73 /* * Iterators return objects, so we need to widen the scope of the * init variable if it, for example, has been assigned double type @@ -1131,7 +1259,7 @@ } @Override - public Node leave(final TernaryNode ternaryNode) { + public Node leaveTernaryNode(final TernaryNode ternaryNode) { final Node lhs = ternaryNode.rhs(); final Node rhs = ternaryNode.third(); @@ -1146,24 +1274,24 @@ return ternaryNode; } - private static void initThis(final FunctionNode functionNode) { - final Symbol thisSymbol = functionNode.defineSymbol(THIS.tag(), IS_PARAM | IS_THIS, null); + private void initThis(final FunctionNode functionNode) { + final Symbol thisSymbol = defineSymbol(functionNode, THIS.tag(), IS_PARAM | IS_THIS, null); newType(thisSymbol, Type.OBJECT); thisSymbol.setNeedsSlot(true); functionNode.getThisNode().setSymbol(thisSymbol); LOG.info("Initialized scope symbol: " + thisSymbol); } - private static void initScope(final FunctionNode functionNode) { - final Symbol scopeSymbol = functionNode.defineSymbol(SCOPE.tag(), IS_VAR | IS_INTERNAL, null); + private void initScope(final FunctionNode functionNode) { + final Symbol scopeSymbol = defineSymbol(functionNode, SCOPE.tag(), IS_VAR | IS_INTERNAL, null); newType(scopeSymbol, Type.typeFor(ScriptObject.class)); scopeSymbol.setNeedsSlot(true); functionNode.getScopeNode().setSymbol(scopeSymbol); LOG.info("Initialized scope symbol: " + scopeSymbol); } - private static void initReturn(final FunctionNode functionNode) { - final Symbol returnSymbol = functionNode.defineSymbol(SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null); + private void initReturn(final FunctionNode functionNode) { + final Symbol returnSymbol = defineSymbol(functionNode, SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null); newType(returnSymbol, Type.OBJECT); returnSymbol.setNeedsSlot(true); functionNode.getResultNode().setSymbol(returnSymbol); @@ -1173,7 +1301,7 @@ private void initVarArg(final FunctionNode functionNode) { if (functionNode.isVarArg()) { - final Symbol varArgsSymbol = functionNode.defineSymbol(VARARGS.tag(), IS_PARAM | IS_INTERNAL, null); + final Symbol varArgsSymbol = defineSymbol(functionNode, VARARGS.tag(), IS_PARAM | IS_INTERNAL, null); varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY); varArgsSymbol.setNeedsSlot(true); functionNode.getVarArgsNode().setSymbol(varArgsSymbol); @@ -1181,7 +1309,7 @@ if (functionNode.needsArguments()) { final String argumentsName = functionNode.getArgumentsNode().getName(); - final Symbol argumentsSymbol = functionNode.defineSymbol(argumentsName, IS_VAR | IS_INTERNAL, null); + final Symbol argumentsSymbol = defineSymbol(functionNode, argumentsName, IS_VAR | IS_INTERNAL, null); newType(argumentsSymbol, Type.typeFor(ScriptObject.class)); argumentsSymbol.setNeedsSlot(true); functionNode.getArgumentsNode().setSymbol(argumentsSymbol); @@ -1191,9 +1319,9 @@ } } - private static void initCallee(final FunctionNode functionNode) { + private void initCallee(final FunctionNode functionNode) { assert functionNode.getCalleeNode() != null : functionNode + " has no callee"; - final Symbol calleeSymbol = functionNode.defineSymbol(CALLEE.tag(), IS_PARAM | IS_INTERNAL, null); + final Symbol calleeSymbol = defineSymbol(functionNode, CALLEE.tag(), IS_PARAM | IS_INTERNAL, null); newType(calleeSymbol, Type.typeFor(ScriptFunction.class)); calleeSymbol.setNeedsSlot(true); functionNode.getCalleeNode().setSymbol(calleeSymbol); @@ -1211,11 +1339,17 @@ // type or its parameters with the widest (OBJECT) type for safety. functionNode.setReturnType(Type.UNKNOWN); - for (final IdentNode ident : functionNode.getParameters()) { - addLocalDef(ident.getName()); - final Symbol paramSymbol = functionNode.defineSymbol(ident.getName(), IS_PARAM, ident); + for (final IdentNode param : functionNode.getParameters()) { + addLocalDef(param.getName()); + final Symbol paramSymbol = defineSymbol(functionNode, param.getName(), IS_PARAM, param); if (paramSymbol != null) { - newType(paramSymbol, Type.UNKNOWN); + final Type callSiteParamType = functionNode.getSpecializedType(param); + if (callSiteParamType != null) { + LOG.info("Param " + paramSymbol + " has a callsite type " + callSiteParamType + ". Using that."); + + System.err.println("Param " + param + " has a callsite type " + callSiteParamType + ". Using that."); + } + newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType); } LOG.info("Initialized param " + paramSymbol); @@ -1229,36 +1363,29 @@ * @param functionNode functionNode */ private static void finalizeParameters(final FunctionNode functionNode) { - boolean nonObjectParams = false; - List paramSpecializations = new ArrayList<>(); + final boolean isVarArg = functionNode.isVarArg(); for (final IdentNode ident : functionNode.getParameters()) { final Symbol paramSymbol = ident.getSymbol(); - if (paramSymbol != null) { - Type type = paramSymbol.getSymbolType(); - if (type.isUnknown()) { - type = Type.OBJECT; - } - paramSpecializations.add(type); - if (!type.isObject()) { - nonObjectParams = true; - } - newType(paramSymbol, Type.OBJECT); + + assert paramSymbol != null; + Type type = functionNode.getSpecializedType(ident); + if (type == null) { + type = Type.OBJECT; } - } - if (!nonObjectParams) { - paramSpecializations = null; - // Later, when resolving a call to this method, the linker can say "I have a double, an int and an object" as parameters - // here. If the callee has parameter specializations, we can regenerate it with those particular types for speed. - } else { - LOG.info("parameter specialization possible: " + functionNode.getName() + " " + paramSpecializations); - } + // if we know that a parameter is only used as a certain type throughout + // this function, we can tell the runtime system that no matter what the + // call site is, use this information. TODO + if (!paramSymbol.getSymbolType().isObject()) { + LOG.finest("Parameter " + ident + " could profit from specialization to " + paramSymbol.getSymbolType()); + } - // parameters should not be slots for a function that uses variable arity signature - if (functionNode.isVarArg()) { - for (final IdentNode param : functionNode.getParameters()) { - param.getSymbol().setNeedsSlot(false); + newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType())); + + // parameters should not be slots for a function that uses variable arity signature + if (isVarArg) { + paramSymbol.setNeedsSlot(false); } } } @@ -1267,15 +1394,15 @@ * Move any properties from a global map into the scope of this method * @param functionNode the function node for which to init scope vars */ - private static void initFromPropertyMap(final FunctionNode functionNode) { + private void initFromPropertyMap(final FunctionNode functionNode) { // For a script, add scope symbols as defined in the property map - assert functionNode.isScript(); + assert functionNode.isProgram(); final PropertyMap map = Context.getGlobalMap(); for (final Property property : map.getProperties()) { final String key = property.getKey(); - final Symbol symbol = functionNode.defineSymbol(key, IS_GLOBAL, null); + final Symbol symbol = defineSymbol(functionNode, key, IS_GLOBAL, null); newType(symbol, Type.OBJECT); LOG.info("Added global symbol from property map " + symbol); } @@ -1342,9 +1469,14 @@ private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) { assignmentDest.accept(new NodeVisitor() { @Override - public Node leave(final IndexNode indexNode) { + public Node leaveIndexNode(final IndexNode indexNode) { + assert indexNode.getSymbol().isTemp(); final Node index = indexNode.getIndex(); - index.getSymbol().setNeedsSlot(!index.getSymbol().isConstant()); + //only temps can be set as needing slots. the others will self resolve + //it is illegal to take a scope var and force it to be a slot, that breaks + if (index.getSymbol().isTemp() && !index.getSymbol().isConstant()) { + index.getSymbol().setNeedsSlot(true); + } return indexNode; } }); @@ -1387,7 +1519,7 @@ } @Override - public Node enter(final FunctionNode node) { + public Node enterFunctionNode(final FunctionNode node) { return node.isLazy() ? null : node; } @@ -1407,7 +1539,7 @@ */ @SuppressWarnings("fallthrough") @Override - public Node leave(final BinaryNode binaryNode) { + public Node leaveBinaryNode(final BinaryNode binaryNode) { final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); switch (binaryNode.tokenType()) { default: @@ -1465,22 +1597,6 @@ return binaryNode; } - private static List findLookupBlocksHelper(final FunctionNode currentFunction, final FunctionNode topFunction) { - if (currentFunction.findParentFunction() == topFunction) { - final List blocks = new LinkedList<>(); - - blocks.add(currentFunction.getParent()); - blocks.addAll(currentFunction.getReferencingParentBlocks()); - return blocks; - } - /* - * assumption: all parent blocks of an inner function will always be in the same outer function; - * therefore we can simply skip through intermediate functions. - * @see FunctionNode#addReferencingParentBlock(Block) - */ - return findLookupBlocksHelper(currentFunction.findParentFunction(), topFunction); - } - private static boolean isFunctionExpressionSelfReference(final Symbol symbol) { if (symbol.isVar() && symbol.getNode() == symbol.getBlock() && symbol.getNode() instanceof FunctionNode) { return ((FunctionNode)symbol.getNode()).getIdent().getName().equals(symbol.getName()); @@ -1497,16 +1613,12 @@ return newTemporary(getCurrentFunctionNode(), type, node); } - private Symbol newInternal(final FunctionNode functionNode, final String name, final Type type) { - final Symbol iter = getCurrentFunctionNode().defineSymbol(name, IS_VAR | IS_INTERNAL, null); + private Symbol newInternal(final String name, final Type type) { + final Symbol iter = defineSymbol(getCurrentFunctionNode(), name, IS_VAR | IS_INTERNAL, null); iter.setType(type); // NASHORN-73 return iter; } - private Symbol newInternal(final String name, final Type type) { - return newInternal(getCurrentFunctionNode(), name, type); - } - private static void newType(final Symbol symbol, final Type type) { final Type oldType = symbol.getSymbolType(); symbol.setType(type); @@ -1548,6 +1660,39 @@ localUses.add(name); } + /** + * Pessimistically promote all symbols in current function node to Object types + * This is done when the function contains unevaluated black boxes such as + * lazy sub-function nodes that have not been compiled. + * + * @param functionNode function node in whose scope symbols should conservatively be made objects + */ + private static void objectifySymbols(final FunctionNode functionNode) { + functionNode.accept(new NodeVisitor() { + private void toObject(final Block block) { + for (final Iterator iter = block.symbolIterator(); iter.hasNext();) { + final Symbol symbol = iter.next(); + newType(symbol, Type.OBJECT); + } + } + + @Override + public Node enterBlock(final Block block) { + toObject(block); + return block; + } + + @Override + public Node enterFunctionNode(final FunctionNode node) { + toObject(node); + if (node.isLazy()) { + return null; + } + return node; + } + }); + } + private static String name(final Node node) { final String cn = node.getClass().getName(); int lastDot = cn.lastIndexOf('.'); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/BranchOptimizer.java --- a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java Tue Mar 26 12:08:00 2013 -0700 @@ -32,7 +32,6 @@ import static jdk.nashorn.internal.codegen.Condition.LT; import static jdk.nashorn.internal.codegen.Condition.NE; -import jdk.nashorn.internal.codegen.Label; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.Node; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/ClassEmitter.java --- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java Tue Mar 26 12:08:00 2013 -0700 @@ -195,6 +195,14 @@ } /** + * Returns the name of the compile unit class name. + * @return the name of the compile unit class name. + */ + String getUnitClassName() { + return unitClassName; + } + + /** * Convert a binary name to a package/class name. * * @param name Binary name. @@ -244,7 +252,7 @@ // $getMap - get the ith entry from the constants table and cast to PropertyMap. final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.tag(), PropertyMap.class, int.class); getMapMethod.begin(); - getMapMethod.loadConstants(unitClassName) + getMapMethod.loadConstants() .load(Type.INT, 0) .arrayload() .checkcast(PropertyMap.class) @@ -254,7 +262,7 @@ // $setMap - overwrite an existing map. final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.tag(), void.class, int.class, PropertyMap.class); setMapMethod.begin(); - setMapMethod.loadConstants(unitClassName) + setMapMethod.loadConstants() .load(Type.INT, 0) .load(Type.OBJECT, 1) .arraystore(); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/CodeGenerator.java --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Mar 26 12:08:00 2013 -0700 @@ -25,10 +25,8 @@ package jdk.nashorn.internal.codegen; -import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.HANDLE_STATIC; import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.PRIVATE; import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.STATIC; -import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE; import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP; import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING; import static jdk.nashorn.internal.codegen.CompilerConstants.LEAF; @@ -50,7 +48,6 @@ import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; import java.io.PrintWriter; -import java.lang.invoke.MethodHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; @@ -79,9 +76,11 @@ import jdk.nashorn.internal.ir.ExecuteNode; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LineNumberNode; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; @@ -89,7 +88,6 @@ import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ObjectNode; import jdk.nashorn.internal.ir.PropertyNode; -import jdk.nashorn.internal.ir.ReferenceNode; import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.RuntimeNode.Request; @@ -108,14 +106,14 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.parser.Lexer.RegexToken; import jdk.nashorn.internal.parser.TokenType; -import jdk.nashorn.internal.runtime.CodeInstaller; import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.ECMAException; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; import jdk.nashorn.internal.runtime.Scope; import jdk.nashorn.internal.runtime.ScriptFunction; -import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.Source; @@ -149,8 +147,6 @@ /** Name of the ScriptFunctionImpl, cannot be referred to as .class @see FunctionObjectCreator */ private static final String SCRIPTFUNCTION_IMPL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionImpl"; - private static final String SCRIPTFUNCTION_TRAMPOLINE_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionTrampolineImpl"; - /** Constant data & installation. The only reason the compiler keeps this is because it is assigned * by reflection in class installation */ private final Compiler compiler; @@ -161,12 +157,20 @@ /** How many regexp fields have been emitted */ private int regexFieldCount; + /** Used for temporary signaling between enterCallNode and enterFunctionNode to handle the special case of calling + * a just-defined anonymous function expression. */ + private boolean functionNodeIsCallee; + /** Map of shared scope call sites */ private final Map scopeCalls = new HashMap<>(); + private final LexicalContext lexicalContext = new LexicalContext(); + /** When should we stop caching regexp expressions in fields to limit bytecode size? */ private static final int MAX_REGEX_FIELDS = 2 * 1024; + private static final DebugLogger LOG = new DebugLogger("codegen", "nashorn.codegen.debug"); + /** * Constructor. * @@ -215,7 +219,7 @@ final int flags = CALLSITE_SCOPE | getCallSiteFlags(); method.loadScope(); - if (symbol.isFastScope(getCurrentFunctionNode())) { + if (isFastScope(symbol)) { // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope. if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) { return loadSharedScopeVar(identNode.getType(), symbol, flags); @@ -226,8 +230,28 @@ } } + /** + * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load + * + * @param function function to check for fast scope + * @return true if fast scope + */ + private boolean isFastScope(final Symbol symbol) { + if (!symbol.isScope() || !symbol.getBlock().needsScope()) { + return false; + } + // Allow fast scope access if no function contains with or eval + for(final Iterator it = lexicalContext.getFunctions(getCurrentFunctionNode()); it.hasNext();) { + final FunctionNode func = it.next(); + if (func.hasWith() || func.hasEval()) { + return false; + } + } + return true; + } + private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) { - method.load(symbol.isFastScope(getCurrentFunctionNode()) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1); + method.load(isFastScope(symbol) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1); final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE); scopeCall.generateInvoke(method); return method; @@ -245,30 +269,18 @@ return method; } - private static int getScopeProtoDepth(final Block currentBlock, final Symbol symbol) { - if (currentBlock == symbol.getBlock()) { - return 0; - } - - final int delta = currentBlock.needsScope() ? 1 : 0; - final Block parentBlock = currentBlock.getParent(); - - if (parentBlock != null) { - final int result = getScopeProtoDepth(parentBlock, symbol); - if (result != -1) { - return delta + result; + private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) { + int depth = 0; + final Block definingBlock = symbol.getBlock(); + for(final Iterator blocks = lexicalContext.getBlocks(startingBlock); blocks.hasNext();) { + final Block currentBlock = blocks.next(); + if (currentBlock == definingBlock) { + return depth; + } + if (currentBlock.needsScope()) { + ++depth; } } - - if (currentBlock instanceof FunctionNode) { - for (final Block lookupBlock : ((FunctionNode)currentBlock).getReferencingParentBlocks()) { - final int result = getScopeProtoDepth(lookupBlock, symbol); - if (result != -1) { - return delta + result; - } - } - } - return -1; } @@ -318,13 +330,13 @@ node.accept(new NodeVisitor(getCurrentCompileUnit(), method) { @Override - public Node enter(final IdentNode identNode) { + public Node enterIdentNode(final IdentNode identNode) { loadIdent(identNode); return null; } @Override - public Node enter(final AccessNode accessNode) { + public Node enterAccessNode(final AccessNode accessNode) { if (!baseAlreadyOnStack) { load(accessNode.getBase()).convert(Type.OBJECT); } @@ -334,7 +346,7 @@ } @Override - public Node enter(final IndexNode indexNode) { + public Node enterIndexNode(final IndexNode indexNode) { if (!baseAlreadyOnStack) { load(indexNode.getBase()).convert(Type.OBJECT); load(indexNode.getIndex()); @@ -344,6 +356,14 @@ } @Override + public Node enterFunctionNode(FunctionNode functionNode) { + // function nodes will always leave a constructed function object on stack, no need to load the symbol + // separately as in enterDefault() + functionNode.accept(codegen); + return null; + } + + @Override public Node enterDefault(final Node otherNode) { otherNode.accept(codegen); // generate code for whatever we are looking at. method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there) @@ -355,7 +375,7 @@ } @Override - public Node enter(final AccessNode accessNode) { + public Node enterAccessNode(final AccessNode accessNode) { if (accessNode.testResolved()) { return null; } @@ -427,10 +447,11 @@ } @Override - public Node enter(final Block block) { + public Node enterBlock(final Block block) { if (block.testResolved()) { return null; } + lexicalContext.push(block); method.label(block.getEntryLabel()); initLocals(block); @@ -439,14 +460,14 @@ } @Override - public Node leave(final Block block) { + public Node leaveBlock(final Block block) { method.label(block.getBreakLabel()); symbolInfo(block); if (block.needsScope()) { popBlockScope(block); } - + lexicalContext.pop(block); return block; } @@ -472,7 +493,7 @@ } @Override - public Node enter(final BreakNode breakNode) { + public Node enterBreakNode(final BreakNode breakNode) { if (breakNode.testResolved()) { return null; } @@ -520,14 +541,13 @@ } @Override - public Node enter(final CallNode callNode) { + public Node enterCallNode(final CallNode callNode) { if (callNode.testResolved()) { return null; } final List args = callNode.getArgs(); final Node function = callNode.getFunction(); - final FunctionNode currentFunction = getCurrentFunctionNode(); final Block currentBlock = getCurrentBlock(); function.accept(new NodeVisitor(getCurrentCompileUnit(), method) { @@ -536,7 +556,7 @@ final Symbol symbol = identNode.getSymbol(); int scopeCallFlags = flags; method.loadScope(); - if (symbol.isFastScope(currentFunction)) { + if (isFastScope(symbol)) { method.load(getScopeProtoDepth(currentBlock, symbol)); scopeCallFlags |= CALLSITE_FAST_SCOPE; } else { @@ -598,7 +618,7 @@ } @Override - public Node enter(final IdentNode node) { + public Node enterIdentNode(final IdentNode node) { final Symbol symbol = node.getSymbol(); if (symbol.isScope()) { @@ -611,7 +631,7 @@ if (callNode.isEval()) { evalCall(node, flags); } else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD - || (!symbol.isFastScope(currentFunction) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD) + || (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD) || callNode.inWithBlock()) { scopeCall(node, flags); } else { @@ -626,7 +646,7 @@ } @Override - public Node enter(final AccessNode node) { + public Node enterAccessNode(final AccessNode node) { load(node.getBase()); method.convert(Type.OBJECT); method.dup(); @@ -639,8 +659,7 @@ } @Override - public Node enter(final ReferenceNode node) { - final FunctionNode callee = node.getReference(); + public Node enterFunctionNode(final FunctionNode callee) { final boolean isVarArg = callee.isVarArg(); final int argCount = isVarArg ? -1 : callee.getParameters().size(); @@ -658,12 +677,13 @@ loadArgs(args, signature, isVarArg, argCount); method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature); assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType(); - + functionNodeIsCallee = true; + callee.accept(CodeGenerator.this); return null; } @Override - public Node enter(final IndexNode node) { + public Node enterIndexNode(final IndexNode node) { load(node.getBase()); method.convert(Type.OBJECT); method.dup(); @@ -699,7 +719,7 @@ } @Override - public Node enter(final ContinueNode continueNode) { + public Node enterContinueNode(final ContinueNode continueNode) { if (continueNode.testResolved()) { return null; } @@ -714,17 +734,17 @@ } @Override - public Node enter(final DoWhileNode doWhileNode) { - return enter((WhileNode)doWhileNode); + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { + return enterWhileNode(doWhileNode); } @Override - public Node enter(final EmptyNode emptyNode) { + public Node enterEmptyNode(final EmptyNode emptyNode) { return null; } @Override - public Node enter(final ExecuteNode executeNode) { + public Node enterExecuteNode(final ExecuteNode executeNode) { if (executeNode.testResolved()) { return null; } @@ -736,7 +756,7 @@ } @Override - public Node enter(final ForNode forNode) { + public Node enterForNode(final ForNode forNode) { if (forNode.testResolved()) { return null; } @@ -818,7 +838,7 @@ * @param block block with local vars. */ private void initLocals(final Block block) { - final FunctionNode function = block.getFunction(); + final FunctionNode function = lexicalContext.getFunction(block); final boolean isFunctionNode = block == function; /* @@ -920,7 +940,7 @@ foc.makeObject(method); // runScript(): merge scope into global - if (isFunctionNode && function.isScript()) { + if (isFunctionNode && function.isProgram()) { method.invoke(ScriptRuntime.MERGE_SCOPE); } @@ -963,31 +983,42 @@ } @Override - public Node enter(final FunctionNode functionNode) { - if (functionNode.isLazy()) { - return null; - } + public Node enterFunctionNode(final FunctionNode functionNode) { + final boolean isCallee = functionNodeIsCallee; + functionNodeIsCallee = false; if (functionNode.testResolved()) { return null; } + if(!(isCallee || functionNode == compiler.getFunctionNode())) { + newFunctionObject(functionNode); + } + + if (functionNode.isLazy()) { + return null; + } + + LOG.info("=== BEGIN " + functionNode.getName()); + lexicalContext.push(functionNode); + setCurrentCompileUnit(functionNode.getCompileUnit()); assert getCurrentCompileUnit() != null; - method = getCurrentCompileUnit().getClassEmitter().method(functionNode); + setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(functionNode)); functionNode.setMethodEmitter(method); // Mark end for variable tables. method.begin(); method.label(functionNode.getEntryLabel()); initLocals(functionNode); + functionNode.setState(CompilationState.EMITTED); return functionNode; } @Override - public Node leave(final FunctionNode functionNode) { + public Node leaveFunctionNode(final FunctionNode functionNode) { // Mark end for variable tables. method.label(functionNode.getBreakLabel()); @@ -1005,16 +1036,18 @@ throw e; } + lexicalContext.pop(functionNode); + LOG.info("=== END " + functionNode.getName()); return functionNode; } @Override - public Node enter(final IdentNode identNode) { + public Node enterIdentNode(final IdentNode identNode) { return null; } @Override - public Node enter(final IfNode ifNode) { + public Node enterIfNode(final IfNode ifNode) { if (ifNode.testResolved()) { return null; } @@ -1053,7 +1086,7 @@ } @Override - public Node enter(final IndexNode indexNode) { + public Node enterIndexNode(final IndexNode indexNode) { if (indexNode.testResolved()) { return null; } @@ -1064,7 +1097,7 @@ } @Override - public Node enter(final LineNumberNode lineNumberNode) { + public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { if (lineNumberNode.testResolved()) { return null; } @@ -1072,7 +1105,6 @@ final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getCurrentFunctionNode().getName() + ")"); method.label(label); method.lineNumber(lineNumberNode.getLineNumber(), label); - return null; } @@ -1110,7 +1142,7 @@ final String name = getCurrentFunctionNode().uniqueName(SPLIT_PREFIX.tag()); final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type); - method = getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature); + setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature)); method.setFunctionNode(getCurrentFunctionNode()); method.begin(); @@ -1216,7 +1248,7 @@ method.invokestatic(unitClassName, methodName, methodDescriptor(cls, int.class)); classEmitter.needGetConstantMethod(cls); } else { - method.loadConstants(unitClassName).load(index).arrayload(); + method.loadConstants().load(index).arrayload(); if (cls != Object.class) { method.checkcast(cls); } @@ -1296,14 +1328,14 @@ @SuppressWarnings("rawtypes") @Override - public Node enter(final LiteralNode literalNode) { + public Node enterLiteralNode(final LiteralNode literalNode) { assert literalNode.getSymbol() != null : literalNode + " has no symbol"; load(literalNode).store(literalNode.getSymbol()); return null; } @Override - public Node enter(final ObjectNode objectNode) { + public Node enterObjectNode(final ObjectNode objectNode) { if (objectNode.testResolved()) { return null; } @@ -1376,10 +1408,10 @@ } for (final Node element : elements) { - final PropertyNode propertyNode = (PropertyNode)element; - final Object key = propertyNode.getKey(); - final ReferenceNode getter = (ReferenceNode)propertyNode.getGetter(); - final ReferenceNode setter = (ReferenceNode)propertyNode.getSetter(); + final PropertyNode propertyNode = (PropertyNode)element; + final Object key = propertyNode.getKey(); + final FunctionNode getter = (FunctionNode)propertyNode.getGetter(); + final FunctionNode setter = (FunctionNode)propertyNode.getSetter(); if (getter == null && setter == null) { continue; @@ -1408,18 +1440,7 @@ } @Override - public Node enter(final ReferenceNode referenceNode) { - if (referenceNode.testResolved()) { - return null; - } - - newFunctionObject(referenceNode.getReference()); - - return null; - } - - @Override - public Node enter(final ReturnNode returnNode) { + public Node enterReturnNode(final ReturnNode returnNode) { if (returnNode.testResolved()) { return null; } @@ -1560,7 +1581,7 @@ } @Override - public Node enter(final RuntimeNode runtimeNode) { + public Node enterRuntimeNode(final RuntimeNode runtimeNode) { if (runtimeNode.testResolved()) { return null; } @@ -1641,7 +1662,7 @@ } @Override - public Node enter(final SplitNode splitNode) { + public Node enterSplitNode(final SplitNode splitNode) { if (splitNode.testResolved()) { return null; } @@ -1710,7 +1731,7 @@ } @Override - public Node leave(final SplitNode splitNode) { + public Node leaveSplitNode(final SplitNode splitNode) { try { // Wrap up this method. method.loadResult(); @@ -1767,7 +1788,7 @@ } @Override - public Node enter(final SwitchNode switchNode) { + public Node enterSwitchNode(final SwitchNode switchNode) { if (switchNode.testResolved()) { return null; } @@ -1899,7 +1920,7 @@ } @Override - public Node enter(final ThrowNode throwNode) { + public Node enterThrowNode(final ThrowNode throwNode) { if (throwNode.testResolved()) { return null; } @@ -1926,7 +1947,7 @@ } @Override - public Node enter(final TryNode tryNode) { + public Node enterTryNode(final TryNode tryNode) { if (tryNode.testResolved()) { return null; } @@ -1959,7 +1980,7 @@ setCurrentBlock(catchBlock); try { - enter(catchBlock); + enterBlock(catchBlock); final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0); final IdentNode exception = catchNode.getException(); @@ -1970,6 +1991,7 @@ // Generate catch body (inlined finally) and rethrow exception catchBody.accept(this); method.load(symbol).athrow(); + lexicalContext.pop(catchBlock); continue; } @@ -2016,7 +2038,7 @@ } } - leave(catchBlock); + leaveBlock(catchBlock); } finally { setCurrentBlock(saveBlock); } @@ -2031,7 +2053,7 @@ } @Override - public Node enter(final VarNode varNode) { + public Node enterVarNode(final VarNode varNode) { final Node init = varNode.getInit(); if (varNode.testResolved() || init == null) { @@ -2053,7 +2075,7 @@ int flags = CALLSITE_SCOPE | getCallSiteFlags(); final IdentNode identNode = varNode.getName(); final Type type = identNode.getType(); - if (varSymbol.isFastScope(getCurrentFunctionNode())) { + if (isFastScope(varSymbol)) { storeFastScopeVar(type, varSymbol, flags); } else { method.dynamicSet(type, identNode.getName(), flags); @@ -2069,7 +2091,7 @@ } @Override - public Node enter(final WhileNode whileNode) { + public Node enterWhileNode(final WhileNode whileNode) { if (whileNode.testResolved()) { return null; } @@ -2102,7 +2124,7 @@ } @Override - public Node enter(final WithNode withNode) { + public Node enterWithNode(final WithNode withNode) { if (withNode.testResolved()) { return null; } @@ -2868,7 +2890,7 @@ * Ternary visits. */ @Override - public Node enter(final TernaryNode ternaryNode) { + public Node enterTernaryNode(final TernaryNode ternaryNode) { if (ternaryNode.testResolved()) { return null; } @@ -3064,7 +3086,7 @@ target.accept(new NodeVisitor(getCurrentCompileUnit(), method) { @Override - public Node enter(final IdentNode node) { + public Node enterIdentNode(final IdentNode node) { if (targetSymbol.isScope()) { method.load(scopeSymbol); depth++; @@ -3087,13 +3109,13 @@ } @Override - public Node enter(final AccessNode node) { + public Node enterAccessNode(final AccessNode node) { enterBaseNode(); return null; } @Override - public Node enter(final IndexNode node) { + public Node enterIndexNode(final IndexNode node) { enterBaseNode(); final Node index = node.getIndex(); @@ -3159,8 +3181,6 @@ } private void epilogue() { - final FunctionNode currentFunction = getCurrentFunctionNode(); - /** * Take the original target args from the stack and use them * together with the value to be stored to emit the store code @@ -3178,7 +3198,7 @@ } @Override - public Node enter(final UnaryNode node) { + public Node enterUnaryNode(final UnaryNode node) { if(node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) { method.convert(node.rhs().getType()); } @@ -3186,11 +3206,11 @@ } @Override - public Node enter(final IdentNode node) { + public Node enterIdentNode(final IdentNode node) { final Symbol symbol = node.getSymbol(); assert symbol != null; if (symbol.isScope()) { - if (symbol.isFastScope(currentFunction)) { + if (isFastScope(symbol)) { storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags()); } else { method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags()); @@ -3203,13 +3223,13 @@ } @Override - public Node enter(final AccessNode node) { + public Node enterAccessNode(final AccessNode node) { method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags()); return null; } @Override - public Node enter(final IndexNode node) { + public Node enterIndexNode(final IndexNode node) { method.dynamicSetIndex(getCallSiteFlags()); return null; } @@ -3234,42 +3254,22 @@ } private void newFunctionObject(final FunctionNode functionNode) { - final boolean isLazy = functionNode.isLazy(); - final Class[] cparams = new Class[] { ScriptFunctionData.class, ScriptObject.class, MethodHandle.class }; + final boolean isLazy = functionNode.isLazy(); new ObjectCreator(this, new ArrayList(), new ArrayList(), false, false) { @Override - protected void makeObject(final MethodEmitter method) { - final String className = isLazy ? SCRIPTFUNCTION_TRAMPOLINE_OBJECT : SCRIPTFUNCTION_IMPL_OBJECT; - - method._new(className).dup(); - if (isLazy) { - loadConstant(compiler.getCodeInstaller()); - loadConstant(functionNode); - } else { - final String signature = new FunctionSignature(true, functionNode.needsCallee(), functionNode.getReturnType(), functionNode.isVarArg() ? null : functionNode.getParameters()).toString(); - method.loadHandle(functionNode.getCompileUnit().getUnitClassName(), functionNode.getName(), signature, EnumSet.of(HANDLE_STATIC)); // function - } - loadConstant(new ScriptFunctionData(functionNode, makeMap())); + protected void makeObject(final MethodEmitter m) { + final String className = SCRIPTFUNCTION_IMPL_OBJECT; + + m._new(className).dup(); + loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), Compiler.binaryName(getClassName()), makeMap())); if (isLazy || functionNode.needsParentScope()) { - method.loadScope(); + m.loadScope(); } else { - method.loadNull(); + m.loadNull(); } - - method.loadHandle(getClassName(), ALLOCATE.tag(), methodDescriptor(ScriptObject.class, PropertyMap.class), EnumSet.of(HANDLE_STATIC)); - - final List> cparamList = new ArrayList<>(); - if (isLazy) { - cparamList.add(CodeInstaller.class); - cparamList.add(FunctionNode.class); - } else { - cparamList.add(MethodHandle.class); - } - cparamList.addAll(Arrays.asList(cparams)); - - method.invoke(constructorNoLookup(className, cparamList.toArray(new Class[cparamList.size()]))); + m.invoke(constructorNoLookup(className, RecompilableScriptFunctionData.class, ScriptObject.class)); } }.makeObject(method); } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/CompilationPhase.java --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java Tue Mar 26 12:08:00 2013 -0700 @@ -2,10 +2,10 @@ import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.ATTR; import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.CONSTANT_FOLDED; -import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.EMITTED; import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.FINALIZED; import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.INITIALIZED; import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOWERED; +import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.PARSED; import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT; import java.io.File; @@ -14,16 +14,16 @@ import java.util.EnumSet; import java.util.HashSet; import java.util.Set; - import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.CallNode; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.Node; -import jdk.nashorn.internal.ir.ReferenceNode; -import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.debug.ASTWriter; import jdk.nashorn.internal.ir.debug.PrintVisitor; +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.runtime.ECMAErrors; import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.Timing; @@ -39,7 +39,7 @@ * default policy. The will get trampolines and only be generated when * called */ - LAZY_INITIALIZATION_PHASE(EnumSet.of(FunctionNode.CompilationState.INITIALIZED)) { + LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) { @Override void transform(final Compiler compiler, final FunctionNode fn) { @@ -65,23 +65,25 @@ outermostFunctionNode.accept(new NodeVisitor() { // self references are done with invokestatic and thus cannot have trampolines - never lazy @Override - public Node enter(final CallNode node) { + public Node enterCallNode(final CallNode node) { final Node callee = node.getFunction(); - if (callee instanceof ReferenceNode) { - neverLazy.add(((ReferenceNode)callee).getReference()); + if (callee instanceof FunctionNode) { + neverLazy.add(((FunctionNode)callee)); return null; } return node; } @Override - public Node enter(final FunctionNode node) { + public Node enterFunctionNode(final FunctionNode node) { if (node == outermostFunctionNode) { return node; } - assert Compiler.LAZY_JIT; + assert compiler.isLazy(); lazy.add(node); + //also needs scope, potentially needs arguments etc etc + return node; } }); @@ -92,15 +94,24 @@ lazy.remove(node); } - for (final FunctionNode node : lazy) { - Compiler.LOG.fine("Marking " + node.getName() + " as lazy"); - node.setIsLazy(true); - final FunctionNode parent = node.findParentFunction(); - if (parent != null) { - Compiler.LOG.fine("Marking " + parent.getName() + " as having lazy children - it needs scope for all variables"); - parent.setHasLazyChildren(); + outermostFunctionNode.accept(new NodeOperatorVisitor() { + private final LexicalContext lexicalContext = new LexicalContext(); + @Override + public Node enterFunctionNode(FunctionNode functionNode) { + lexicalContext.push(functionNode); + if(lazy.contains(functionNode)) { + Compiler.LOG.fine("Marking " + functionNode.getName() + " as lazy"); + functionNode.setIsLazy(true); + lexicalContext.getParentFunction(functionNode).setHasLazyChildren(); + } + return functionNode; } - } + @Override + public Node leaveFunctionNode(FunctionNode functionNode) { + lexicalContext.pop(functionNode); + return functionNode; + } + }); } @Override @@ -113,7 +124,7 @@ * Constant folding pass * Simple constant folding that will make elementary constructs go away */ - CONSTANT_FOLDING_PHASE(EnumSet.of(INITIALIZED), CONSTANT_FOLDED) { + CONSTANT_FOLDING_PHASE(EnumSet.of(INITIALIZED, PARSED)) { @Override void transform(final Compiler compiler, final FunctionNode fn) { fn.accept(new FoldConstants()); @@ -134,7 +145,7 @@ * as runtime nodes where applicable. * */ - LOWERING_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED), LOWERED) { + LOWERING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED)) { @Override void transform(final Compiler compiler, final FunctionNode fn) { fn.accept(new Lower()); @@ -150,19 +161,10 @@ * Attribution * Assign symbols and types to all nodes. */ - ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED), ATTR) { + ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) { @Override void transform(final Compiler compiler, final FunctionNode fn) { - final ScriptEnvironment env = compiler.getEnv(); - fn.accept(new Attr()); - if (env._print_lower_ast) { - env.getErr().println(new ASTWriter(fn)); - } - - if (env._print_lower_parse) { - env.getErr().println(new PrintVisitor(fn)); - } } @Override @@ -178,7 +180,7 @@ * a + b a ScriptRuntime.ADD with call overhead or a dadd with much * less). Split IR can lead to scope information being changed. */ - SPLITTING_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR), SPLIT) { + SPLITTING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) { @Override void transform(final Compiler compiler, final FunctionNode fn) { final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); @@ -212,10 +214,20 @@ * Contract: all variables must have slot assignments and scope assignments * before type finalization. */ - TYPE_FINALIZATION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT), FINALIZED) { + TYPE_FINALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT)) { @Override void transform(final Compiler compiler, final FunctionNode fn) { + final ScriptEnvironment env = compiler.getEnv(); + fn.accept(new FinalizeTypes()); + + if (env._print_lower_ast) { + env.getErr().println(new ASTWriter(fn)); + } + + if (env._print_lower_parse) { + env.getErr().println(new PrintVisitor(fn)); + } } @Override @@ -229,7 +241,7 @@ * * Generate the byte code class(es) resulting from the compiled FunctionNode */ - BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED), EMITTED) { + BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED)) { @Override void transform(final Compiler compiler, final FunctionNode fn) { final ScriptEnvironment env = compiler.getEnv(); @@ -238,6 +250,16 @@ final CodeGenerator codegen = new CodeGenerator(compiler); fn.accept(codegen); codegen.generateScopeCalls(); + fn.accept(new NodeOperatorVisitor() { + @Override + public Node enterFunctionNode(FunctionNode functionNode) { + if(functionNode.isLazy()) { + functionNode.resetResolved(); + return null; + } + return fn; + } + }); } catch (final VerifyError e) { if (env._verify_code || env._print_code) { @@ -306,18 +328,12 @@ }; private final EnumSet pre; - private final CompilationState post; private long startTime; private long endTime; private boolean isFinished; private CompilationPhase(final EnumSet pre) { - this(pre, null); - } - - private CompilationPhase(final EnumSet pre, final CompilationState post) { - this.pre = pre; - this.post = post; + this.pre = pre; } boolean isApplicable(final FunctionNode functionNode) { @@ -343,10 +359,6 @@ endTime = System.currentTimeMillis(); Timing.accumulateTime(toString(), endTime - startTime); - if (post != null) { - functionNode.setState(post); - } - isFinished = true; } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/CompileUnit.java --- a/src/jdk/nashorn/internal/codegen/CompileUnit.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java Tue Mar 26 12:08:00 2013 -0700 @@ -37,6 +37,8 @@ private long weight; + private Class clazz; + CompileUnit(final String className, final ClassEmitter classEmitter) { this(className, classEmitter, 0L); } @@ -48,6 +50,24 @@ } /** + * Return the class that contains the code for this unit, null if not + * generated yet + * + * @return class with compile unit code + */ + public Class getCode() { + return clazz; + } + + /** + * Set class when it exists. Only accessible from compiler + * @param clazz class with code for this compile unit + */ + void setCode(final Class clazz) { + this.clazz = clazz; + } + + /** * Add weight to this compile unit * @param w weight to add */ diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/Compiler.java --- a/src/jdk/nashorn/internal/codegen/Compiler.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Tue Mar 26 12:08:00 2013 -0700 @@ -45,11 +45,14 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.logging.Level; import jdk.internal.dynalink.support.NameCodec; import jdk.nashorn.internal.codegen.ClassEmitter.Flag; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.runtime.CodeInstaller; import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.ScriptEnvironment; @@ -71,8 +74,6 @@ /** Name of the objects package */ public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects"; - static final boolean LAZY_JIT = Options.getBooleanProperty("nashorn.compiler.lazy"); - private final Map bytecode; private final Set compileUnits; @@ -164,7 +165,7 @@ * and JIT it at once. This can lead to long startup time and fewer type * specializations */ - final static CompilationSequence SEQUENCE_NORMAL = new CompilationSequence( + final static CompilationSequence SEQUENCE_EAGER = new CompilationSequence( CompilationPhase.CONSTANT_FOLDING_PHASE, CompilationPhase.LOWERING_PHASE, CompilationPhase.ATTRIBUTION_PHASE, @@ -173,12 +174,15 @@ CompilationPhase.BYTECODE_GENERATION_PHASE); final static CompilationSequence SEQUENCE_LAZY = - SEQUENCE_NORMAL.insertFirst(CompilationPhase.LAZY_INITIALIZATION_PHASE); + SEQUENCE_EAGER.insertFirst(CompilationPhase.LAZY_INITIALIZATION_PHASE); - final static CompilationSequence SEQUENCE_DEFAULT = - LAZY_JIT ? - SEQUENCE_LAZY : - SEQUENCE_NORMAL; + private static CompilationSequence sequence(final boolean lazy) { + return lazy ? SEQUENCE_LAZY : SEQUENCE_EAGER; + } + + boolean isLazy() { + return sequence == SEQUENCE_LAZY; + } private static String lazyTag(final FunctionNode functionNode) { if (functionNode.isLazy()) { @@ -212,11 +216,6 @@ append(safeSourceName(functionNode.getSource())); this.scriptName = sb.toString(); - - LOG.info("Initializing compiler for '" + functionNode.getName() + "' scriptName = " + scriptName + ", root function: '" + functionNode.getName() + "'"); - if (functionNode.isLazy()) { - LOG.info(">>> This is a lazy recompilation triggered by a trampoline"); - } } /** @@ -227,7 +226,7 @@ * @param strict should this compilation use strict mode semantics */ public Compiler(final CodeInstaller installer, final FunctionNode functionNode, final boolean strict) { - this(installer.getOwner(), installer, functionNode, SEQUENCE_DEFAULT, strict); + this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), strict); } /** @@ -237,7 +236,7 @@ * @param functionNode function node (in any available {@link CompilationState}) to compile */ public Compiler(final CodeInstaller installer, final FunctionNode functionNode) { - this(installer.getOwner(), installer, functionNode, SEQUENCE_DEFAULT, installer.getOwner()._strict); + this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict); } /** @@ -247,28 +246,104 @@ * @param functionNode functionNode to compile */ public Compiler(final ScriptEnvironment env, final FunctionNode functionNode) { - this(env, null, functionNode, SEQUENCE_DEFAULT, env._strict); + this(env, null, functionNode, sequence(env._lazy_compilation), env._strict); + } + + /** + * Execute the compilation this Compiler was created with + * @params param types if known, for specialization + * @throws CompilationException if something goes wrong + * @return this compiler, for possible chaining + */ + public Compiler compile() throws CompilationException { + return compile(null); } /** * Execute the compilation this Compiler was created with + * @param paramTypes param types if known, for specialization * @throws CompilationException if something goes wrong + * @return this compiler, for possible chaining */ - public void compile() throws CompilationException { + public Compiler compile(final Class paramTypes) throws CompilationException { for (final String reservedName : RESERVED_NAMES) { functionNode.uniqueName(reservedName); } + final boolean fine = !LOG.levelAbove(Level.FINE); + final boolean info = !LOG.levelAbove(Level.INFO); + + long time = 0L; + for (final CompilationPhase phase : sequence) { phase.apply(this, functionNode); - final String end = phase.toString() + " done for function '" + functionNode.getName() + "'"; - if (Timing.isEnabled()) { - final long duration = phase.getEndTime() - phase.getStartTime(); - LOG.info(end + " in " + duration + " ms"); - } else { - LOG.info(end); + + final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L; + time += duration; + + if (fine) { + final StringBuilder sb = new StringBuilder(); + + sb.append(phase.toString()). + append(" done for function '"). + append(functionNode.getName()). + append('\''); + + if (duration > 0L) { + sb.append(" in "). + append(duration). + append(" ms "); + } + + LOG.fine(sb.toString()); } } + + if (info) { + final StringBuilder sb = new StringBuilder(); + sb.append("Compile job for '"). + append(functionNode.getName()). + append("' finished"); + + if (time > 0L) { + sb.append(" in "). + append(time). + append(" ms"); + } + + LOG.info(sb.toString()); + } + + return this; + } + + private Class install(final String className, final byte[] code) { + LOG.fine("Installing class " + className); + + final Class clazz = installer.install(Compiler.binaryName(className), code); + + try { + final Source source = getSource(); + final Object[] constants = getConstantData().toArray(); + // Need doPrivileged because these fields are private + AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Void run() throws Exception { + //use reflection to write source and constants table to installed classes + final Field sourceField = clazz.getDeclaredField(SOURCE.tag()); + final Field constantsField = clazz.getDeclaredField(CONSTANTS.tag()); + sourceField.setAccessible(true); + constantsField.setAccessible(true); + sourceField.set(null, source); + constantsField.set(null, constants); + return null; + } + }); + } catch (final PrivilegedActionException e) { + throw new RuntimeException(e); + } + + return clazz; } /** @@ -280,46 +355,68 @@ assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed"; - Class rootClass = null; + final Map> installedClasses = new HashMap<>(); + + final String rootClassName = firstCompileUnitName(); + final byte[] rootByteCode = bytecode.get(rootClassName); + final Class rootClass = install(rootClassName, rootByteCode); + + int length = rootByteCode.length; + + installedClasses.put(rootClassName, rootClass); for (final Entry entry : bytecode.entrySet()) { - final String className = entry.getKey(); - LOG.fine("Installing class " + className); + final String className = entry.getKey(); + if (className.equals(rootClassName)) { + continue; + } + final byte[] code = entry.getValue(); + length += code.length; - final byte[] code = entry.getValue(); - final Class clazz = installer.install(Compiler.binaryName(className), code); + installedClasses.put(className, install(className, code)); + } - if (rootClass == null && firstCompileUnitName().equals(className)) { - rootClass = clazz; - } + for (final CompileUnit unit : compileUnits) { + unit.setCode(installedClasses.get(unit.getUnitClassName())); + } - try { - final Source source = getSource(); - final Object[] constants = getConstantData().toArray(); - // Need doPrivileged because these fields are private - AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public Void run() throws Exception { - //use reflection to write source and constants table to installed classes - final Field sourceField = clazz.getDeclaredField(SOURCE.tag()); - final Field constantsField = clazz.getDeclaredField(CONSTANTS.tag()); - sourceField.setAccessible(true); - constantsField.setAccessible(true); - sourceField.set(null, source); - constantsField.set(null, constants); - return null; - } - }); - } catch (final PrivilegedActionException e) { - throw new RuntimeException(e); + functionNode.accept(new NodeVisitor() { + @Override + public Node enterFunctionNode(final FunctionNode node) { + if (node.isLazy()) { + return null; + } + node.setState(CompilationState.INSTALLED); + return node; + } + }); + + final StringBuilder sb; + if (LOG.isEnabled()) { + sb = new StringBuilder(); + sb.append("Installed class '"). + append(rootClass.getSimpleName()). + append('\''). + append(" bytes="). + append(length). + append('.'); + if (bytecode.size() > 1) { + sb.append(' ').append(bytecode.size()).append(" compile units."); + } + } else { + sb = null; + } + + if (Timing.isEnabled()) { + final long duration = System.currentTimeMillis() - t0; + Timing.accumulateTime("[Code Installation]", duration); + if (sb != null) { + sb.append(" Install time: ").append(duration).append(" ms"); } } - LOG.info("Installed root class: " + rootClass + " and " + bytecode.size() + " compile unit classes"); - if (Timing.isEnabled()) { - final long duration = System.currentTimeMillis() - t0; - Timing.accumulateTime("[Code Installation]", duration); - LOG.info("Installation time: " + duration + " ms"); + if (sb != null) { + LOG.info(sb.toString()); } return rootClass; @@ -444,8 +541,6 @@ * TODO: We currently generate no overflow checks so this is * disabled * - * @see #shouldUseIntegers() - * * @return true if arithmetic operations should not widen integer * operands by default. */ @@ -460,4 +555,5 @@ assert !USE_INT_ARITH : "Integer arithmetic is not enabled"; } + } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/FinalizeTypes.java --- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue Mar 26 12:08:00 2013 -0700 @@ -40,13 +40,14 @@ import jdk.nashorn.internal.ir.ExecuteNode; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.Node; -import jdk.nashorn.internal.ir.ReferenceNode; import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.RuntimeNode.Request; @@ -84,11 +85,13 @@ private static final DebugLogger LOG = new DebugLogger("finalize"); + private final LexicalContext lexicalContext = new LexicalContext(); + FinalizeTypes() { } @Override - public Node leave(final CallNode callNode) { + public Node leaveCallNode(final CallNode callNode) { final EvalArgs evalArgs = callNode.getEvalArgs(); if (evalArgs != null) { evalArgs.setCode(evalArgs.getCode().accept(this)); @@ -96,15 +99,14 @@ // AccessSpecializer - call return type may change the access for this location final Node function = callNode.getFunction(); - if (function instanceof ReferenceNode) { - setTypeOverride(callNode, ((ReferenceNode)function).getReference().getType()); + if (function instanceof FunctionNode) { + return setTypeOverride(callNode, ((FunctionNode)function).getReturnType()); } return callNode; } private Node leaveUnary(final UnaryNode unaryNode) { - unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType())); - return unaryNode; + return unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType())); } @Override @@ -125,8 +127,7 @@ @Override public Node leaveDECINC(final UnaryNode unaryNode) { - specialize(unaryNode); - return unaryNode; + return specialize(unaryNode).node; } @Override @@ -158,9 +159,7 @@ } } - binaryNode.setLHS(convert(lhs, type)); - binaryNode.setRHS(convert(rhs, type)); - return binaryNode; + return binaryNode.setLHS(convert(lhs, type)).setRHS(convert(rhs, type)); } @Override @@ -170,12 +169,13 @@ @Override public Node leaveASSIGN(final BinaryNode binaryNode) { - Type destType = specialize(binaryNode); + final SpecializedNode specialized = specialize(binaryNode); + final BinaryNode specBinaryNode = (BinaryNode)specialized.node; + Type destType = specialized.type; if (destType == null) { - destType = binaryNode.getType(); + destType = specBinaryNode.getType(); } - binaryNode.setRHS(convert(binaryNode.rhs(), destType)); - return binaryNode; + return specBinaryNode.setRHS(convert(specBinaryNode.rhs(), destType)); } @Override @@ -235,40 +235,40 @@ @Override public Node leaveBIT_AND(BinaryNode binaryNode) { - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : binaryNode.getSymbol(); + assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); return leaveBinary(binaryNode, Type.INT, Type.INT); } @Override public Node leaveBIT_OR(BinaryNode binaryNode) { - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger(); + assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); return leaveBinary(binaryNode, Type.INT, Type.INT); } @Override public Node leaveBIT_XOR(BinaryNode binaryNode) { - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger(); + assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); return leaveBinary(binaryNode, Type.INT, Type.INT); } @Override public Node leaveCOMMALEFT(final BinaryNode binaryNode) { assert binaryNode.getSymbol() != null; - binaryNode.setRHS(discard(binaryNode.rhs())); - // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed + final BinaryNode newBinaryNode = (BinaryNode)binaryNode.setRHS(discard(binaryNode.rhs())); + // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed // in that case, update the node type as well - propagateType(binaryNode, binaryNode.lhs().getType()); - return binaryNode; + propagateType(newBinaryNode, newBinaryNode.lhs().getType()); + return newBinaryNode; } @Override public Node leaveCOMMARIGHT(final BinaryNode binaryNode) { assert binaryNode.getSymbol() != null; - binaryNode.setLHS(discard(binaryNode.lhs())); + final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs())); // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed // in that case, update the node type as well - propagateType(binaryNode, binaryNode.rhs().getType()); - return binaryNode; + propagateType(newBinaryNode, newBinaryNode.rhs().getType()); + return newBinaryNode; } @Override @@ -344,7 +344,7 @@ @Override public Node leaveSHR(final BinaryNode binaryNode) { - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isLong(); + assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isLong() : "long coercion expected: " + binaryNode.getSymbol(); return leaveBinary(binaryNode, Type.INT, Type.INT); } @@ -354,13 +354,20 @@ } @Override - public Node enter(final Block block) { + public Node enterBlock(final Block block) { + lexicalContext.push(block); updateSymbols(block); return block; } @Override - public Node leave(final CatchNode catchNode) { + public Node leaveBlock(Block block) { + lexicalContext.pop(block); + return super.leaveBlock(block); + } + + @Override + public Node leaveCatchNode(final CatchNode catchNode) { final Node exceptionCondition = catchNode.getExceptionCondition(); if (exceptionCondition != null) { catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN)); @@ -369,23 +376,23 @@ } @Override - public Node enter(final DoWhileNode doWhileNode) { - return enter((WhileNode)doWhileNode); + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { + return enterWhileNode(doWhileNode); } @Override - public Node leave(final DoWhileNode doWhileNode) { - return leave((WhileNode)doWhileNode); + public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { + return leaveWhileNode(doWhileNode); } @Override - public Node leave(final ExecuteNode executeNode) { + public Node leaveExecuteNode(final ExecuteNode executeNode) { executeNode.setExpression(discard(executeNode.getExpression())); return executeNode; } @Override - public Node leave(final ForNode forNode) { + public Node leaveForNode(final ForNode forNode) { final Node init = forNode.getInit(); final Node test = forNode.getTest(); final Node modify = forNode.getModify(); @@ -413,11 +420,12 @@ } @Override - public Node enter(final FunctionNode functionNode) { + public Node enterFunctionNode(final FunctionNode functionNode) { if (functionNode.isLazy()) { return null; } + lexicalContext.push(functionNode); // If the function doesn't need a callee, we ensure its __callee__ symbol doesn't get a slot. We can't do // this earlier, as access to scoped variables, self symbol, etc. in previous phases can all trigger the // need for the callee. @@ -432,18 +440,26 @@ } updateSymbols(functionNode); + functionNode.setState(CompilationState.FINALIZED); + return functionNode; } @Override - public Node leave(final IfNode ifNode) { + public Node leaveFunctionNode(FunctionNode functionNode) { + lexicalContext.pop(functionNode); + return super.leaveFunctionNode(functionNode); + } + + @Override + public Node leaveIfNode(final IfNode ifNode) { ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN)); return ifNode; } @SuppressWarnings("rawtypes") @Override - public Node enter(final LiteralNode literalNode) { + public Node enterLiteralNode(final LiteralNode literalNode) { if (literalNode instanceof ArrayLiteralNode) { final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode; final Node[] array = arrayLiteralNode.getValue(); @@ -461,7 +477,7 @@ } @Override - public Node leave(final ReturnNode returnNode) { + public Node leaveReturnNode(final ReturnNode returnNode) { final Node expr = returnNode.getExpression(); if (expr != null) { returnNode.setExpression(convert(expr, getCurrentFunctionNode().getReturnType())); @@ -470,7 +486,7 @@ } @Override - public Node leave(final RuntimeNode runtimeNode) { + public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { final List args = runtimeNode.getArgs(); for (final Node arg : args) { assert !arg.getType().isUnknown(); @@ -479,7 +495,7 @@ } @Override - public Node leave(final SwitchNode switchNode) { + public Node leaveSwitchNode(final SwitchNode switchNode) { final Node expression = switchNode.getExpression(); final List cases = switchNode.getCases(); final boolean allInteger = switchNode.getTag().getSymbolType().isInteger(); @@ -498,34 +514,34 @@ } @Override - public Node leave(final TernaryNode ternaryNode) { - ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN)); - return ternaryNode; + public Node leaveTernaryNode(final TernaryNode ternaryNode) { + return ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN)); } @Override - public Node leave(final ThrowNode throwNode) { + public Node leaveThrowNode(final ThrowNode throwNode) { throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT)); return throwNode; } @Override - public Node leave(final VarNode varNode) { - + public Node leaveVarNode(final VarNode varNode) { final Node rhs = varNode.getInit(); if (rhs != null) { - Type destType = specialize(varNode); + final SpecializedNode specialized = specialize(varNode); + final VarNode specVarNode = (VarNode)specialized.node; + Type destType = specialized.type; if (destType == null) { - destType = varNode.getType(); + destType = specVarNode.getType(); } - assert varNode.hasType() : varNode + " doesn't have a type"; - varNode.setInit(convert(rhs, destType)); + assert specVarNode.hasType() : specVarNode + " doesn't have a type"; + return specVarNode.setInit(convert(rhs, destType)); } return varNode; } @Override - public Node leave(final WhileNode whileNode) { + public Node leaveWhileNode(final WhileNode whileNode) { final Node test = whileNode.getTest(); if (test != null) { whileNode.setTest(convert(test, Type.BOOLEAN)); @@ -534,7 +550,7 @@ } @Override - public Node leave(final WithNode withNode) { + public Node leaveWithNode(final WithNode withNode) { withNode.setExpression(convert(withNode.getExpression(), Type.OBJECT)); return withNode; } @@ -553,14 +569,14 @@ * that scope and slot information is correct for every symbol * @param block block for which to to finalize type info. */ - private static void updateSymbols(final Block block) { + private void updateSymbols(final Block block) { if (!block.needsScope()) { return; // nothing to do } - assert !(block instanceof FunctionNode) || block.getFunction() == block; + final FunctionNode functionNode = lexicalContext.getFunction(block); + assert !(block instanceof FunctionNode) || functionNode == block; - final FunctionNode functionNode = block.getFunction(); final List symbols = block.getFrame().getSymbols(); final boolean allVarsInScope = functionNode.allVarsInScope(); final boolean isVarArg = functionNode.isVarArg(); @@ -629,10 +645,7 @@ break; } - binaryNode.setLHS(convert(lhs, widest)); - binaryNode.setRHS(convert(rhs, widest)); - - return binaryNode; + return binaryNode.setLHS(convert(lhs, widest)).setRHS(convert(rhs, widest)); } /** @@ -654,9 +667,7 @@ } private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) { - binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)); - binaryNode.setRHS(convert(binaryNode.rhs(), rhsType)); - return binaryNode; + return binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType)); } /** @@ -677,7 +688,7 @@ } @Override - public Node enter(final IdentNode identNode) { + public Node enterIdentNode(final IdentNode identNode) { if (!exclude.contains(identNode)) { setCanBePrimitive(identNode.getSymbol()); } @@ -685,26 +696,36 @@ } @Override - public Node enter(final AccessNode accessNode) { + public Node enterAccessNode(final AccessNode accessNode) { setCanBePrimitive(accessNode.getProperty().getSymbol()); return null; } @Override - public Node enter(final IndexNode indexNode) { + public Node enterIndexNode(final IndexNode indexNode) { exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine return indexNode; } }); } - private static Type specialize(final Assignment assignment) { + private static class SpecializedNode { + final Node node; + final Type type; + + SpecializedNode(Node node, Type type) { + this.node = node; + this.type = type; + } + } + + private static SpecializedNode specialize(final Assignment assignment) { final Node node = ((Node)assignment); - final Node lhs = assignment.getAssignmentDest(); + final T lhs = assignment.getAssignmentDest(); final Node rhs = assignment.getAssignmentSource(); if (!canHaveCallSiteType(lhs)) { - return null; + return new SpecializedNode(node, null); } final Type to; @@ -716,13 +737,13 @@ if (!isSupportedCallSiteType(to)) { //meaningless to specialize to boolean or object - return null; + return new SpecializedNode(node, null); } - setTypeOverride(lhs, to); - propagateType(node, to); + final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to)); + propagateType(newNode, to); - return to; + return new SpecializedNode(newNode, to); } @@ -734,7 +755,7 @@ * @return true if node can have a callsite type */ private static boolean canHaveCallSiteType(final Node node) { - return node instanceof TypeOverride && ((TypeOverride)node).canHaveCallSiteType(); + return node instanceof TypeOverride && ((TypeOverride)node).canHaveCallSiteType(); } /** @@ -760,7 +781,8 @@ * @param node node for which to change type * @param to new type */ - private static void setTypeOverride(final Node node, final Type to) { + @SuppressWarnings("unchecked") + private static T setTypeOverride(final T node, final Type to) { final Type from = node.getType(); if (!node.getType().equals(to)) { LOG.info("Changing call override type for '" + node + "' from " + node.getType() + " to " + to); @@ -769,7 +791,7 @@ } } LOG.info("Type override for lhs in '" + node + "' => " + to); - ((TypeOverride)node).setType(to); + return ((TypeOverride)node).setType(to); } /** @@ -814,8 +836,8 @@ } } else { if (canHaveCallSiteType(node) && isSupportedCallSiteType(to)) { - setTypeOverride(node, to); - return resultNode; + assert node instanceof TypeOverride; + return setTypeOverride(node, to); } resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node); } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/FoldConstants.java --- a/src/jdk/nashorn/internal/codegen/FoldConstants.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java Tue Mar 26 12:08:00 2013 -0700 @@ -30,6 +30,8 @@ import jdk.nashorn.internal.ir.Block; import jdk.nashorn.internal.ir.EmptyNode; import jdk.nashorn.internal.ir.ExecuteNode; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.Node; @@ -52,7 +54,7 @@ } @Override - public Node leave(final UnaryNode unaryNode) { + public Node leaveUnaryNode(final UnaryNode unaryNode) { final LiteralNode literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval(); if (literalNode != null) { LOG.info("Unary constant folded " + unaryNode + " to " + literalNode); @@ -62,7 +64,7 @@ } @Override - public Node leave(final BinaryNode binaryNode) { + public Node leaveBinaryNode(final BinaryNode binaryNode) { final LiteralNode literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval(); if (literalNode != null) { LOG.info("Binary constant folded " + binaryNode + " to " + literalNode); @@ -72,7 +74,21 @@ } @Override - public Node leave(final IfNode ifNode) { + public Node enterFunctionNode(final FunctionNode functionNode) { + if (functionNode.isLazy()) { + return null; + } + return functionNode; + } + + @Override + public Node leaveFunctionNode(final FunctionNode functionNode) { + functionNode.setState(CompilationState.CONSTANT_FOLDED); + return functionNode; + } + + @Override + public Node leaveIfNode(final IfNode ifNode) { final Node test = ifNode.getTest(); if (test instanceof LiteralNode) { final Block shortCut = ((LiteralNode)test).isTrue() ? ifNode.getPass() : ifNode.getFail(); @@ -85,7 +101,7 @@ } @Override - public Node leave(final TernaryNode ternaryNode) { + public Node leaveTernaryNode(final TernaryNode ternaryNode) { final Node test = ternaryNode.lhs(); if (test instanceof LiteralNode) { return ((LiteralNode)test).isTrue() ? ternaryNode.rhs() : ternaryNode.third(); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/FunctionSignature.java --- a/src/jdk/nashorn/internal/codegen/FunctionSignature.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/FunctionSignature.java Tue Mar 26 12:08:00 2013 -0700 @@ -146,7 +146,7 @@ /** * Create a function signature given a function node, using as much - * type information for parameters and return types that is availabe + * type information for parameters and return types that is available * * @param functionNode the function node */ @@ -155,7 +155,7 @@ true, functionNode.needsCallee(), functionNode.getReturnType(), - (functionNode.isVarArg() && !functionNode.isScript()) ? + (functionNode.isVarArg() && !functionNode.isProgram()) ? null : functionNode.getParameters()); } @@ -202,6 +202,14 @@ return methodType; } + /** + * Return the return type for this function signature + * @return the return type + */ + public Type getReturnType() { + return returnType; + } + private static Type[] objectArgs(final int nArgs) { final Type[] array = new Type[nArgs]; for (int i = 0; i < nArgs; i++) { diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/Lower.java --- a/src/jdk/nashorn/internal/codegen/Lower.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/Lower.java Tue Mar 26 12:08:00 2013 -0700 @@ -37,8 +37,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Deque; +import java.util.Iterator; import java.util.List; -import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.BaseNode; import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.Block; @@ -52,11 +52,12 @@ import jdk.nashorn.internal.ir.ExecuteNode; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; -import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LabeledNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LineNumberNode; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.Node; @@ -102,6 +103,8 @@ private List statements; + private LexicalContext lexicalContext = new LexicalContext(); + /** * Constructor. * @@ -113,14 +116,15 @@ } @Override - public Node enter(final Block block) { + public Node enterBlock(final Block block) { final Node savedLastStatement = lastStatement; final List savedStatements = statements; - + lexicalContext.push(block); try { this.statements = new ArrayList<>(); + NodeVisitor visitor = this; for (final Node statement : block.getStatements()) { - statement.accept(this); + statement.accept(visitor); /* * This is slightly unsound, for example if we have a loop with * a guarded statement like if (x) continue in the body and the @@ -132,7 +136,7 @@ */ if (lastStatement != null && lastStatement.isTerminal()) { copyTerminal(block, lastStatement); - break; + visitor = new DeadCodeVarDeclarationVisitor(); } } block.setStatements(statements); @@ -140,18 +144,19 @@ } finally { this.statements = savedStatements; this.lastStatement = savedLastStatement; + lexicalContext.pop(block); } return null; } @Override - public Node enter(final BreakNode breakNode) { + public Node enterBreakNode(final BreakNode breakNode) { return enterBreakOrContinue(breakNode); } @Override - public Node enter(final CallNode callNode) { + public Node enterCallNode(final CallNode callNode) { final Node function = markerFunction(callNode.getFunction()); callNode.setFunction(function); checkEval(callNode); //check if this is an eval call and store the information @@ -159,44 +164,44 @@ } @Override - public Node leave(final CaseNode caseNode) { + public Node leaveCaseNode(final CaseNode caseNode) { caseNode.copyTerminalFlags(caseNode.getBody()); return caseNode; } @Override - public Node leave(final CatchNode catchNode) { + public Node leaveCatchNode(final CatchNode catchNode) { catchNode.copyTerminalFlags(catchNode.getBody()); addStatement(catchNode); return catchNode; } @Override - public Node enter(final ContinueNode continueNode) { + public Node enterContinueNode(final ContinueNode continueNode) { return enterBreakOrContinue(continueNode); } @Override - public Node enter(final DoWhileNode doWhileNode) { - return enter((WhileNode)doWhileNode); + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { + return enterWhileNode(doWhileNode); } @Override - public Node leave(final DoWhileNode doWhileNode) { - return leave((WhileNode)doWhileNode); + public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { + return leaveWhileNode(doWhileNode); } @Override - public Node enter(final EmptyNode emptyNode) { + public Node enterEmptyNode(final EmptyNode emptyNode) { return null; } @Override - public Node leave(final ExecuteNode executeNode) { + public Node leaveExecuteNode(final ExecuteNode executeNode) { final Node expr = executeNode.getExpression(); - if (getCurrentFunctionNode().isScript()) { - if (!(expr instanceof Block)) { + if (getCurrentFunctionNode().isProgram()) { + if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) { executeNode.setExpression(new BinaryNode(executeNode.getSource(), Token.recast(executeNode.getToken(), TokenType.ASSIGN), getCurrentFunctionNode().getResultNode(), @@ -212,13 +217,13 @@ } @Override - public Node enter(final ForNode forNode) { + public Node enterForNode(final ForNode forNode) { nest(forNode); return forNode; } @Override - public Node leave(final ForNode forNode) { + public Node leaveForNode(final ForNode forNode) { final Node test = forNode.getTest(); final Block body = forNode.getBody(); @@ -236,6 +241,7 @@ if (!forNode.isForIn() && conservativeAlwaysTrue(test)) { forNode.setTest(null); + setHasGoto(forNode); setTerminal(forNode, !escapes); } @@ -245,18 +251,16 @@ } @Override - public Node enter(final FunctionNode functionNode) { + public Node enterFunctionNode(final FunctionNode functionNode) { LOG.info("START FunctionNode: " + functionNode.getName()); if (functionNode.isLazy()) { LOG.info("LAZY: " + functionNode.getName()); return null; } - + lexicalContext.push(functionNode); initFunctionNode(functionNode); - Node initialEvalResult = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED); - nest(functionNode); /* @@ -270,60 +274,40 @@ statements = new ArrayList<>(); lastStatement = null; - // for initial eval result is the last declared function - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { - final IdentNode ident = nestedFunction.getIdent(); - if (ident != null && nestedFunction.isStatement()) { - initialEvalResult = new IdentNode(ident); - } - } - if (functionNode.needsSelfSymbol()) { //function needs to start with var funcIdent = __callee_; statements.add(functionNode.getSelfSymbolInit().accept(this)); } + NodeVisitor visitor = this; try { - // Every nested function needs a definition in the outer function with its name. Add these. - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { - final VarNode varNode = nestedFunction.getFunctionVarNode(); - if (varNode != null) { - final LineNumberNode lineNumberNode = nestedFunction.getFunctionVarLineNumberNode(); - if (lineNumberNode != null) { - lineNumberNode.accept(this); - } - varNode.accept(this); - varNode.setIsFunctionVarNode(); + //do the statements - this fills the block with code + boolean needsInitialEvalResult = functionNode.isProgram(); + for (final Node statement : functionNode.getStatements()) { + // If this function is a program, then insert an assignment to the initial eval result after all + // function declarations. + if(needsInitialEvalResult && !(statement instanceof LineNumberNode || (statement instanceof VarNode && ((VarNode)statement).isFunctionDeclaration()))) { + addInitialEvalResult(functionNode); + needsInitialEvalResult = false; } - } - - if (functionNode.isScript()) { - new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(), initialEvalResult).accept(this); - } - - //do the statements - this fills the block with code - for (final Node statement : functionNode.getStatements()) { - statement.accept(this); + statement.accept(visitor); //If there are unused terminated endpoints in the function, we need // to add a "return undefined" in those places for correct semantics LOG.info("Checking lastStatement="+lastStatement+" for terminal flags"); if (lastStatement != null && lastStatement.hasTerminalFlags()) { copyTerminal(functionNode, lastStatement); - break; + assert !needsInitialEvalResult; + visitor = new DeadCodeVarDeclarationVisitor(); } } - + if(needsInitialEvalResult) { + addInitialEvalResult(functionNode); + } functionNode.setStatements(statements); if (!functionNode.isTerminal()) { guaranteeReturn(functionNode); } - - //lower all nested functions - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { - nestedFunction.accept(this); - } - } finally { statements = savedStatements; lastStatement = savedLastStatement; @@ -331,17 +315,67 @@ LOG.info("END FunctionNode: " + functionNode.getName()); unnest(functionNode); + lexicalContext.pop(functionNode); + + functionNode.setState(CompilationState.LOWERED); return null; } + /** + * This visitor is used to go over statements after a terminal statement. Those statements are dead code, but the + * var declarations in them still have the effect of declaring a local variable on the function level. Therefore, + * they aren't really dead code and must be preserved. Note that they're only preserved as no-op declarations; their + * initializers are wiped out as those are, in fact, dead code. + */ + private class DeadCodeVarDeclarationVisitor extends NodeOperatorVisitor { + DeadCodeVarDeclarationVisitor() { + } + + @Override + public Node enterVarNode(VarNode varNode) { + // Can't ever see a function declaration, as this visitor is only ever used after a terminal statement was + // encountered, and all function declarations precede any terminal statements. + assert !varNode.isFunctionDeclaration(); + if(varNode.getInit() == null) { + // No initializer, just pass it to Lower. + return varNode.accept(Lower.this); + } + // Wipe out the initializer and then pass it to Lower. + return varNode.setInit(null).accept(Lower.this); + } + } + + private void addInitialEvalResult(final FunctionNode functionNode) { + new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(), + getInitialEvalResult(functionNode)).accept(this); + } + + /** + * Result of initial result of evaluating a particular program, which is either the last function it declares, or + * undefined if it doesn't declare any functions. + * @param program + * @return the initial result of evaluating the program + */ + private static Node getInitialEvalResult(final FunctionNode program) { + IdentNode lastFnName = null; + for (final FunctionNode fn : program.getDeclaredFunctions()) { + assert fn.isDeclared(); + final IdentNode fnName = fn.getIdent(); + if(fnName != null) { + lastFnName = fnName; + } + } + return lastFnName != null ? new IdentNode(lastFnName) : LiteralNode.newInstance(program, ScriptRuntime.UNDEFINED); + } + @Override - public Node enter(final IfNode ifNode) { + public Node enterIfNode(final IfNode ifNode) { return nest(ifNode); } @Override - public Node leave(final IfNode ifNode) { + public Node leaveIfNode(final IfNode ifNode) { final Node pass = ifNode.getPass(); final Node fail = ifNode.getFail(); @@ -356,7 +390,7 @@ } @Override - public Node enter(LabelNode labelNode) { + public Node enterLabelNode(LabelNode labelNode) { final Block body = labelNode.getBody(); body.accept(this); copyTerminal(labelNode, body); @@ -365,13 +399,13 @@ } @Override - public Node enter(final LineNumberNode lineNumberNode) { + public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { addStatement(lineNumberNode, false); // don't put it in lastStatement cache return null; } @Override - public Node enter(final ReturnNode returnNode) { + public Node enterReturnNode(final ReturnNode returnNode) { final TryNode tryNode = returnNode.getTryChain(); final Node expr = returnNode.getExpression(); @@ -409,19 +443,19 @@ } @Override - public Node leave(final ReturnNode returnNode) { + public Node leaveReturnNode(final ReturnNode returnNode) { addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor return returnNode; } @Override - public Node enter(final SwitchNode switchNode) { + public Node enterSwitchNode(final SwitchNode switchNode) { nest(switchNode); return switchNode; } @Override - public Node leave(final SwitchNode switchNode) { + public Node leaveSwitchNode(final SwitchNode switchNode) { unnest(switchNode); final List cases = switchNode.getCases(); @@ -442,13 +476,13 @@ } @Override - public Node leave(final ThrowNode throwNode) { + public Node leaveThrowNode(final ThrowNode throwNode) { addStatement(throwNode); //ThrowNodes are always terminal, marked as such in constructor return throwNode; } @Override - public Node enter(final TryNode tryNode) { + public Node enterTryNode(final TryNode tryNode) { final Block finallyBody = tryNode.getFinallyBody(); final long token = tryNode.getToken(); final int finish = tryNode.getFinish(); @@ -534,26 +568,19 @@ // set outer tryNode's body to innerTryNode final Block outerBody; - outerBody = new Block(source, token, finish, tryNode.getBody().getParent(), getCurrentFunctionNode()); + outerBody = new Block(source, token, finish); outerBody.setStatements(new ArrayList(Arrays.asList(innerTryNode))); tryNode.setBody(outerBody); tryNode.setCatchBlocks(null); - - // now before we go on, we have to fix the block parents - // (we repair the block tree after the insertion so that all references are intact) - innerTryNode.getBody().setParent(tryNode.getBody()); - for (final Block block : innerTryNode.getCatchBlocks()) { - block.setParent(tryNode.getBody()); - } } // create a catch-all that inlines finally and rethrows - final Block catchBlock = new Block(source, token, finish, getCurrentBlock(), getCurrentFunctionNode()); + final Block catchBlock = new Block(source, token, finish); //this catch block should get define symbol - final Block catchBody = new Block(source, token, finish, catchBlock, getCurrentFunctionNode()); - final Node catchAllFinally = finallyBody.clone(); + final Block catchBody = new Block(source, token, finish); + final Node catchAllFinally = finallyBody.copy(); catchBody.addStatement(new ExecuteNode(source, finallyBody.getToken(), finallyBody.getFinish(), catchAllFinally)); setTerminal(catchBody, true); @@ -580,7 +607,7 @@ } @Override - public Node leave(final TryNode tryNode) { + public Node leaveTryNode(final TryNode tryNode) { final Block finallyBody = tryNode.getFinallyBody(); boolean allTerminal = tryNode.getBody().isTerminal() && (finallyBody == null || finallyBody.isTerminal()); @@ -604,18 +631,18 @@ } @Override - public Node leave(final VarNode varNode) { + public Node leaveVarNode(final VarNode varNode) { addStatement(varNode); return varNode; } @Override - public Node enter(final WhileNode whileNode) { + public Node enterWhileNode(final WhileNode whileNode) { return nest(whileNode); } @Override - public Node leave(final WhileNode whileNode) { + public Node leaveWhileNode(final WhileNode whileNode) { final Node test = whileNode.getTest(); if (test == null) { @@ -636,7 +663,7 @@ } else if (conservativeAlwaysTrue(test)) { node = new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish()); ((ForNode)node).setBody(body); - ((ForNode)node).accept(this); + node.accept(this); setTerminal(node, !escapes); } } @@ -649,7 +676,7 @@ } @Override - public Node leave(final WithNode withNode) { + public Node leaveWithNode(final WithNode withNode) { if (withNode.getBody().isTerminal()) { setTerminal(withNode, true); } @@ -678,28 +705,10 @@ */ private static Node markerFunction(final Node function) { if (function instanceof IdentNode) { - return new IdentNode((IdentNode)function) { - @Override - public boolean isFunction() { - return true; - } - }; - } else if (function instanceof AccessNode) { - return new AccessNode((AccessNode)function) { - @Override - public boolean isFunction() { - return true; - } - }; - } else if (function instanceof IndexNode) { - return new IndexNode((IndexNode)function) { - @Override - public boolean isFunction() { - return true; - } - }; + return ((IdentNode)function).setIsFunction(); + } else if (function instanceof BaseNode) { + return ((BaseNode)function).setIsFunction(); } - return function; } @@ -742,7 +751,7 @@ if (args.size() >= 1 && EVAL.tag().equals(callee.getName())) { final CallNode.EvalArgs evalArgs = new CallNode.EvalArgs( - args.get(0).clone().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case" + args.get(0).copy().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case" getCurrentFunctionNode().getThisNode(), evalLocation(callee), getCurrentFunctionNode().isStrictMode()); @@ -769,13 +778,13 @@ loopBody.accept(new NodeVisitor() { @Override - public Node leave(final BreakNode node) { + public Node leaveBreakNode(final BreakNode node) { escapes.add(node); return node; } @Override - public Node leave(final ContinueNode node) { + public Node leaveContinueNode(final ContinueNode node) { // all inner loops have been popped. if (nesting.contains(node.getTargetNode())) { escapes.add(node); @@ -790,7 +799,7 @@ private void guaranteeReturn(final FunctionNode functionNode) { Node resultNode; - if (functionNode.isScript()) { + if (functionNode.isProgram()) { resultNode = functionNode.getResultNode(); // the eval result, symbol assigned in Attr } else { if (lastStatement != null && lastStatement.isTerminal() || lastStatement instanceof ReturnNode) { @@ -855,18 +864,15 @@ * @return true if try block is inside the target, false otherwise. */ private boolean isNestedTry(final TryNode tryNode, final Block target) { - for (Block current = getCurrentBlock(); current != target; current = current.getParent()) { - if (tryNode.getBody() == current) { + for(Iterator blocks = lexicalContext.getBlocks(getCurrentBlock()); blocks.hasNext();) { + final Block block = blocks.next(); + if(block == target) { + return false; + } + if(tryNode.isChildBlock(block)) { return true; } - - for (final Block catchBlock : tryNode.getCatchBlocks()) { - if (catchBlock == current) { - return true; - } - } } - return false; } @@ -895,7 +901,7 @@ continue; } - finallyBody = (Block)finallyBody.clone(); + finallyBody = (Block)finallyBody.copy(); final boolean hasTerminalFlags = finallyBody.hasTerminalFlags(); new ExecuteNode(finallyBody.getSource(), finallyBody.getToken(), finallyBody.getFinish(), finallyBody).accept(this); @@ -970,6 +976,3 @@ } } - - - diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/MethodEmitter.java --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java Tue Mar 26 12:08:00 2013 -0700 @@ -651,11 +651,10 @@ /** * Load the constants array - * @param unitClassName name of the compile unit from which to load constants * @return this method emitter */ - MethodEmitter loadConstants(final String unitClassName) { - getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor()); + MethodEmitter loadConstants() { + getStatic(classEmitter.getUnitClassName(), CONSTANTS.tag(), CONSTANTS.descriptor()); assert peekType().isArray() : peekType(); return this; } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/Splitter.java --- a/src/jdk/nashorn/internal/codegen/Splitter.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/Splitter.java Tue Mar 26 12:08:00 2013 -0700 @@ -39,7 +39,9 @@ import jdk.nashorn.internal.ir.DoWhileNode; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.LabelNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; @@ -48,6 +50,7 @@ import jdk.nashorn.internal.ir.SplitNode; import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.WhileNode; +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.Source; @@ -69,6 +72,8 @@ /** Cache for calculated block weights. */ private final Map weightCache = new HashMap<>(); + private final LexicalContext lexicalContext = new LexicalContext(); + /** Weight threshold for when to start a split. */ public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024); @@ -92,15 +97,16 @@ */ void split() { if (functionNode.isLazy()) { - LOG.fine("Postponing split of '" + functionNode.getName() + "' as it's lazy"); + LOG.finest("Postponing split of '" + functionNode.getName() + "' as it's lazy"); return; } - LOG.fine("Initiating split of '" + functionNode.getName() + "'"); + + LOG.finest("Initiating split of '" + functionNode.getName() + "'"); long weight = WeighNodes.weigh(functionNode); if (weight >= SPLIT_THRESHOLD) { - LOG.fine("Splitting '" + functionNode.getName() + "' as its weight " + weight + " exceeds split threshold " + SPLIT_THRESHOLD); + LOG.finest("Splitting '" + functionNode.getName() + "' as its weight " + weight + " exceeds split threshold " + SPLIT_THRESHOLD); functionNode.accept(this); @@ -110,7 +116,7 @@ } if (weight >= SPLIT_THRESHOLD) { - weight = splitBlock(functionNode); + weight = splitBlock(functionNode, functionNode); } if (functionNode.isSplit()) { @@ -130,9 +136,22 @@ } // Recursively split nested functions - for (final FunctionNode function : functionNode.getFunctions()) { - new Splitter(compiler, function, outermostCompileUnit).split(); - } + functionNode.accept(new NodeOperatorVisitor() { + @Override + public Node enterFunctionNode(FunctionNode function) { + if(function == functionNode) { + // Don't process outermost function (it was already processed) but descend into it to find nested + // functions. + return function; + } + // Process a nested function + new Splitter(compiler, function, outermostCompileUnit).split(); + // Don't descend into a a nested function; Splitter.split() has taken care of nested-in-nested functions. + return null; + } + }); + + functionNode.setState(CompilationState.SPLIT); } /** @@ -151,7 +170,7 @@ * * @return new weight for the resulting block. */ - private long splitBlock(final Block block) { + private long splitBlock(final Block block, final FunctionNode function) { functionNode.setIsSplit(); final List splits = new ArrayList<>(); @@ -163,7 +182,7 @@ if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) { if (!statements.isEmpty()) { - splits.add(createBlockSplitNode(block, statements, statementsWeight)); + splits.add(createBlockSplitNode(block, function, statements, statementsWeight)); statements = new ArrayList<>(); statementsWeight = 0; } @@ -179,7 +198,7 @@ } if (!statements.isEmpty()) { - splits.add(createBlockSplitNode(block, statements, statementsWeight)); + splits.add(createBlockSplitNode(block, function, statements, statementsWeight)); } block.setStatements(splits); @@ -195,13 +214,13 @@ * * @return New split node. */ - private SplitNode createBlockSplitNode(final Block parent, final List statements, final long weight) { + private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List statements, final long weight) { final Source source = parent.getSource(); final long token = parent.getToken(); final int finish = parent.getFinish(); - final String name = parent.getFunction().uniqueName(SPLIT_PREFIX.tag()); + final String name = function.uniqueName(SPLIT_PREFIX.tag()); - final Block newBlock = new Block(source, token, finish, parent, functionNode); + final Block newBlock = new Block(source, token, finish); newBlock.setFrame(new Frame(parent.getFrame())); newBlock.setStatements(statements); @@ -213,15 +232,17 @@ } @Override - public Node enter(final Block block) { + public Node enterBlock(final Block block) { if (block.isCatchBlock()) { return null; } + lexicalContext.push(block); final long weight = WeighNodes.weigh(block, weightCache); if (weight < SPLIT_THRESHOLD) { weightCache.put(block, weight); + lexicalContext.pop(block); return null; } @@ -229,23 +250,24 @@ } @Override - public Node leave(final Block block) { + public Node leaveBlock(final Block block) { assert !block.isCatchBlock(); // Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have // been split already, so weigh again before splitting. long weight = WeighNodes.weigh(block, weightCache); if (weight >= SPLIT_THRESHOLD) { - weight = splitBlock(block); + weight = splitBlock(block, lexicalContext.getFunction(block)); } weightCache.put(block, weight); + lexicalContext.pop(block); return block; } @SuppressWarnings("rawtypes") @Override - public Node leave(final LiteralNode literal) { + public Node leaveLiteralNode(final LiteralNode literal) { long weight = WeighNodes.weigh(literal); if (weight < SPLIT_THRESHOLD) { @@ -290,17 +312,12 @@ } @Override - public Node enter(final FunctionNode node) { - if (node.isLazy()) { - return null; + public Node enterFunctionNode(final FunctionNode node) { + if(node == functionNode && !node.isLazy()) { + lexicalContext.push(node); + node.visitStatements(this); + lexicalContext.pop(node); } - - final List statements = node.getStatements(); - - for (final Node statement : statements) { - statement.accept(this); - } - return null; } @@ -317,38 +334,38 @@ } @Override - public Node enter(final LabelNode labelNode) { + public Node enterLabelNode(final LabelNode labelNode) { registerJumpTarget(labelNode.getBreakNode()); registerJumpTarget(labelNode.getContinueNode()); return labelNode; } @Override - public Node enter(final WhileNode whileNode) { + public Node enterWhileNode(final WhileNode whileNode) { registerJumpTarget(whileNode); return whileNode; } @Override - public Node enter(final DoWhileNode doWhileNode) { + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { registerJumpTarget(doWhileNode); return doWhileNode; } @Override - public Node enter(final ForNode forNode) { + public Node enterForNode(final ForNode forNode) { registerJumpTarget(forNode); return forNode; } @Override - public Node enter(final SwitchNode switchNode) { + public Node enterSwitchNode(final SwitchNode switchNode) { registerJumpTarget(switchNode); return switchNode; } @Override - public Node enter(final ReturnNode returnNode) { + public Node enterReturnNode(final ReturnNode returnNode) { for (final SplitNode split : splitStack) { split.setHasReturn(true); } @@ -356,25 +373,25 @@ } @Override - public Node enter(final ContinueNode continueNode) { + public Node enterContinueNode(final ContinueNode continueNode) { searchJumpTarget(continueNode.getTargetNode(), continueNode.getTargetLabel()); return continueNode; } @Override - public Node enter(final BreakNode breakNode) { + public Node enterBreakNode(final BreakNode breakNode) { searchJumpTarget(breakNode.getTargetNode(), breakNode.getTargetLabel()); return breakNode; } @Override - public Node enter(final SplitNode splitNode) { + public Node enterSplitNode(final SplitNode splitNode) { splitStack.addFirst(splitNode); return splitNode; } @Override - public Node leave(final SplitNode splitNode) { + public Node leaveSplitNode(final SplitNode splitNode) { assert splitNode == splitStack.peekFirst(); splitStack.removeFirst(); return splitNode; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/WeighNodes.java --- a/src/jdk/nashorn/internal/codegen/WeighNodes.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java Tue Mar 26 12:08:00 2013 -0700 @@ -47,7 +47,6 @@ import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.PropertyNode; -import jdk.nashorn.internal.ir.ReferenceNode; import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.SplitNode; @@ -80,7 +79,7 @@ private static final long LITERAL_WEIGHT = 10; private static final long LOOP_WEIGHT = 4; private static final long NEW_WEIGHT = 6; - private static final long REFERENCE_WEIGHT = 20; + private static final long FUNC_EXPR_WEIGHT = 20; private static final long RETURN_WEIGHT = 2; private static final long SPLIT_WEIGHT = 40; private static final long SWITCH_WEIGHT = 8; @@ -94,36 +93,37 @@ /** Optional cache for weight of block nodes. */ private final Map weightCache; - /* + private final FunctionNode topFunction; + + /** * Constructor * * @param weightCache cache of already calculated block weights */ - private WeighNodes(final Map weightCache) { + private WeighNodes(FunctionNode topFunction, final Map weightCache) { super(null, null); + this.topFunction = topFunction; this.weightCache = weightCache; } static long weigh(final Node node) { - final WeighNodes weighNodes = new WeighNodes(null); - node.accept(weighNodes); - return weighNodes.weight; + return weigh(node, null); } static long weigh(final Node node, final Map weightCache) { - final WeighNodes weighNodes = new WeighNodes(weightCache); + final WeighNodes weighNodes = new WeighNodes(node instanceof FunctionNode ? (FunctionNode)node : null, weightCache); node.accept(weighNodes); return weighNodes.weight; } @Override - public Node leave(final AccessNode accessNode) { + public Node leaveAccessNode(final AccessNode accessNode) { weight += ACCESS_WEIGHT; return accessNode; } @Override - public Node enter(final Block block) { + public Node enterBlock(final Block block) { if (weightCache != null && weightCache.containsKey(block)) { weight += weightCache.get(block); return null; @@ -133,78 +133,79 @@ } @Override - public Node leave(final BreakNode breakNode) { + public Node leaveBreakNode(final BreakNode breakNode) { weight += BREAK_WEIGHT; return breakNode; } @Override - public Node leave(final CallNode callNode) { + public Node leaveCallNode(final CallNode callNode) { weight += CALL_WEIGHT; return callNode; } @Override - public Node leave(final CatchNode catchNode) { + public Node leaveCatchNode(final CatchNode catchNode) { weight += CATCH_WEIGHT; return catchNode; } @Override - public Node leave(final ContinueNode continueNode) { + public Node leaveContinueNode(final ContinueNode continueNode) { weight += CONTINUE_WEIGHT; return continueNode; } @Override - public Node leave(final DoWhileNode doWhileNode) { + public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { weight += LOOP_WEIGHT; return doWhileNode; } @Override - public Node leave(final ExecuteNode executeNode) { + public Node leaveExecuteNode(final ExecuteNode executeNode) { return executeNode; } @Override - public Node leave(final ForNode forNode) { + public Node leaveForNode(final ForNode forNode) { weight += LOOP_WEIGHT; return forNode; } @Override - public Node enter(final FunctionNode functionNode) { - final List statements = functionNode.getStatements(); - - for (final Node statement : statements) { - statement.accept(this); + public Node enterFunctionNode(final FunctionNode functionNode) { + if(functionNode == topFunction) { + // the function being weighted; descend into its statements + functionNode.visitStatements(this); + } else { + // just a reference to inner function from outer function + weight += FUNC_EXPR_WEIGHT; } - return null; } @Override - public Node leave(final IdentNode identNode) { + public Node leaveIdentNode(final IdentNode identNode) { weight += ACCESS_WEIGHT + identNode.getName().length() * 2; return identNode; } @Override - public Node leave(final IfNode ifNode) { + public Node leaveIfNode(final IfNode ifNode) { weight += IF_WEIGHT; return ifNode; } @Override - public Node leave(final IndexNode indexNode) { + public Node leaveIndexNode(final IndexNode indexNode) { weight += ACCESS_WEIGHT; return indexNode; } @SuppressWarnings("rawtypes") @Override - public Node enter(final LiteralNode literalNode) { + public Node enterLiteralNode(final LiteralNode literalNode) { weight += LITERAL_WEIGHT; if (literalNode instanceof ArrayLiteralNode) { @@ -230,67 +231,61 @@ } @Override - public Node leave(final PropertyNode propertyNode) { + public Node leavePropertyNode(final PropertyNode propertyNode) { weight += LITERAL_WEIGHT; return propertyNode; } @Override - public Node leave(final ReferenceNode referenceNode) { - weight += REFERENCE_WEIGHT; - return referenceNode; - } - - @Override - public Node leave(final ReturnNode returnNode) { + public Node leaveReturnNode(final ReturnNode returnNode) { weight += RETURN_WEIGHT; return returnNode; } @Override - public Node leave(final RuntimeNode runtimeNode) { + public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { weight += CALL_WEIGHT; return runtimeNode; } @Override - public Node enter(final SplitNode splitNode) { + public Node enterSplitNode(final SplitNode splitNode) { weight += SPLIT_WEIGHT; return null; } @Override - public Node leave(final SwitchNode switchNode) { + public Node leaveSwitchNode(final SwitchNode switchNode) { weight += SWITCH_WEIGHT; return switchNode; } @Override - public Node leave(final ThrowNode throwNode) { + public Node leaveThrowNode(final ThrowNode throwNode) { weight += THROW_WEIGHT; return throwNode; } @Override - public Node leave(final TryNode tryNode) { + public Node leaveTryNode(final TryNode tryNode) { weight += THROW_WEIGHT; return tryNode; } @Override - public Node leave(final VarNode varNode) { + public Node leaveVarNode(final VarNode varNode) { weight += VAR_WEIGHT; return varNode; } @Override - public Node leave(final WhileNode whileNode) { + public Node leaveWhileNode(final WhileNode whileNode) { weight += LOOP_WEIGHT; return whileNode; } @Override - public Node leave(final WithNode withNode) { + public Node leaveWithNode(final WithNode withNode) { weight += WITH_WEIGHT; return withNode; } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/codegen/types/Type.java --- a/src/jdk/nashorn/internal/codegen/types/Type.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java Tue Mar 26 12:08:00 2013 -0700 @@ -647,21 +647,20 @@ } private static void swap(final MethodVisitor method, final Type above, final Type below) { - final MethodVisitor mv = method; if (below.isCategory2()) { if (above.isCategory2()) { - mv.visitInsn(DUP2_X2); - mv.visitInsn(POP2); + method.visitInsn(DUP2_X2); + method.visitInsn(POP2); } else { - mv.visitInsn(DUP_X2); - mv.visitInsn(POP); + method.visitInsn(DUP_X2); + method.visitInsn(POP); } } else { if (above.isCategory2()) { - mv.visitInsn(DUP2_X1); - mv.visitInsn(POP2); + method.visitInsn(DUP2_X1); + method.visitInsn(POP2); } else { - mv.visitInsn(SWAP); + method.visitInsn(SWAP); } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/AccessNode.java --- a/src/jdk/nashorn/internal/ir/AccessNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/AccessNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -36,7 +36,7 @@ * IR representation of a property access (period operator.) * */ -public class AccessNode extends BaseNode implements TypeOverride { +public class AccessNode extends BaseNode implements TypeOverride { /** Property ident. */ private IdentNode property; @@ -56,9 +56,7 @@ super(source, token, finish, base); this.start = base.getStart(); - this.property = property; - - this.property.setIsPropertyName(); + this.property = property.setIsPropertyName(); } /** @@ -106,10 +104,10 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterAccessNode(this) != null) { base = base.accept(visitor); property = (IdentNode)property.accept(visitor); - return visitor.leave(this); + return visitor.leaveAccessNode(this); } return this; @@ -150,13 +148,14 @@ } @Override - public void setType(final Type type) { + public AccessNode setType(final Type type) { if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType()); } - property.setType(type); + property = property.setType(type); getSymbol().setTypeOverride(type); //always a temp so this is fine. hasCallSiteType = true; + return this; } @Override diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/Assignment.java --- a/src/jdk/nashorn/internal/ir/Assignment.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/Assignment.java Tue Mar 26 12:08:00 2013 -0700 @@ -46,4 +46,11 @@ * @return get the assignment source node */ public Node getAssignmentSource(); + + /** + * Set assignment destination node. + * @param n the assignment destination node. + * @return a node equivalent to this one except for the requested change. + */ + public Node setAssignmentDest(D n); } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/BaseNode.java --- a/src/jdk/nashorn/internal/ir/BaseNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/BaseNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -38,6 +38,8 @@ /** Base Node. */ protected Node base; + private boolean function; + /** * Constructor * @@ -96,6 +98,15 @@ @Override public boolean isFunction() { - return false; + return function; + } + + /** + * Mark this node as being the callee operand of a {@link CallNode}. + * @return a base node identical to this one in all aspects except with its function flag set. + */ + public BaseNode setIsFunction() { + function = true; + return this; } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/BinaryNode.java --- a/src/jdk/nashorn/internal/ir/BinaryNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -35,7 +35,7 @@ */ public class BinaryNode extends UnaryNode { /** Left hand side argument. */ - protected Node lhs; + private Node lhs; /** * Constructor @@ -140,6 +140,11 @@ } @Override + public Node setAssignmentDest(Node n) { + return setLHS(n); + } + + @Override public Node getAssignmentSource() { return rhs(); } @@ -163,10 +168,9 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - lhs = lhs.accept(visitor); - rhs = rhs.accept(visitor); - return visitor.leave(this); + if (visitor.enterBinaryNode(this) != null) { + // TODO: good cause for a separate visitMembers: we could delegate to UnaryNode.visitMembers + return visitor.leaveBinaryNode((BinaryNode)setLHS(lhs.accept(visitor)).setRHS(rhs().accept(visitor))); } return this; @@ -229,8 +233,12 @@ /** * Set the left hand side expression for this node * @param lhs new left hand side expression + * @return a node equivalent to this one except for the requested change. */ - public void setLHS(final Node lhs) { - this.lhs = lhs; + public BinaryNode setLHS(final Node lhs) { + if(this.lhs == lhs) return this; + final BinaryNode n = (BinaryNode)clone(); + n.lhs = lhs; + return n; } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/Block.java --- a/src/jdk/nashorn/internal/ir/Block.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/Block.java Tue Mar 26 12:08:00 2013 -0700 @@ -25,41 +25,24 @@ package jdk.nashorn.internal.ir; -import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL; -import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; -import static jdk.nashorn.internal.ir.Symbol.IS_LET; -import static jdk.nashorn.internal.ir.Symbol.IS_PARAM; -import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE; -import static jdk.nashorn.internal.ir.Symbol.IS_VAR; -import static jdk.nashorn.internal.ir.Symbol.KINDMASK; - import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import jdk.nashorn.internal.codegen.Frame; import jdk.nashorn.internal.codegen.Label; -import jdk.nashorn.internal.ir.annotations.Ignore; -import jdk.nashorn.internal.ir.annotations.ParentNode; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.runtime.Source; /** * IR representation for a list of statements and functions. All provides the * basis for script body. - * */ public class Block extends Node { - /** Parent context */ - @ParentNode @Ignore - private Block parent; - - /** Owning function. */ - @Ignore //don't print it, it is apparent in the tree - protected FunctionNode function; - /** List of statements */ protected List statements; @@ -84,14 +67,10 @@ * @param source source code * @param token token * @param finish finish - * @param parent reference to parent block - * @param function function node this block is in */ - public Block(final Source source, final long token, final int finish, final Block parent, final FunctionNode function) { + public Block(final Source source, final long token, final int finish) { super(source, token, finish); - this.parent = parent; - this.function = function; this.statements = new ArrayList<>(); this.symbols = new HashMap<>(); this.entryLabel = new Label("block_entry"); @@ -107,8 +86,6 @@ protected Block(final Block block, final CopyState cs) { super(block); - this.parent = block.parent; - this.function = block.function; this.statements = new ArrayList<>(); for (final Node statement : block.getStatements()) { statements.add(cs.existingOrCopy(statement)); @@ -123,55 +100,7 @@ @Override protected Node copy(final CopyState cs) { - return fixBlockChain(new Block(this, cs)); - } - - /** - * Whenever a clone that contains a hierarchy of blocks is created, - * this function has to be called to ensure that the parents point - * to the correct parent blocks or two different ASTs would not - * be completely separated. - * - * @return the argument - */ - static Block fixBlockChain(final Block root) { - root.accept(new NodeVisitor() { - private Block parent = root.getParent(); - private final FunctionNode function = root.getFunction(); - - @Override - public Node enter(final Block block) { - assert block.getFunction() == function; - block.setParent(parent); - parent = block; - - return block; - } - - @Override - public Node leave(final Block block) { - parent = block.getParent(); - - return block; - } - - @Override - public Node enter(final FunctionNode functionNode) { - assert functionNode.getFunction() == function; - - return enter((Block)functionNode); - } - - @Override - public Node leave(final FunctionNode functionNode) { - assert functionNode.getFunction() == function; - - return leave((Block)functionNode); - } - - }); - - return root; + return new Block(this, cs); } /** @@ -189,17 +118,12 @@ } /** - * Prepend a statement to the statement list + * Prepend statements to the statement list * - * @param statement Statement node to add + * @param prepended statement to add */ - public void prependStatement(final Node statement) { - if (statement != null) { - final List newStatements = new ArrayList<>(); - newStatements.add(statement); - newStatements.addAll(statements); - setStatements(newStatements); - } + public void prependStatements(final List prepended) { + statements.addAll(0, prepended); } /** @@ -212,39 +136,6 @@ } /** - * Add a new function to the function list. - * - * @param functionNode Function node to add. - */ - public void addFunction(final FunctionNode functionNode) { - assert parent != null : "Parent context missing."; - - parent.addFunction(functionNode); - } - - /** - * Add a list of functions to the function list. - * - * @param functionNodes Function nodes to add. - */ - public void addFunctions(final List functionNodes) { - assert parent != null : "Parent context missing."; - - parent.addFunctions(functionNodes); - } - - /** - * Set the function list to a new one - * - * @param functionNodes the nodes to set - */ - public void setFunctions(final List functionNodes) { - assert parent != null : "Parent context missing."; - - parent.setFunctions(functionNodes); - } - - /** * Assist in IR navigation. * * @param visitor IR navigating visitor. @@ -258,13 +149,9 @@ try { // Ignore parent to avoid recursion. - if (visitor.enter(this) != null) { - for (int i = 0, count = statements.size(); i < count; i++) { - final Node statement = statements.get(i); - statements.set(i, statement.accept(visitor)); - } - - return visitor.leave(this); + if (visitor.enterBlock(this) != null) { + visitStatements(visitor); + return visitor.leaveBlock(this); } } finally { visitor.setCurrentBlock(saveBlock); @@ -274,51 +161,21 @@ } /** - * Search for symbol. - * - * @param name Symbol name. - * - * @return Found symbol or null if not found. + * Get an iterator for all the symbols defined in this block + * @return symbol iterator */ - public Symbol findSymbol(final String name) { - // Search up block chain to locate symbol. - - for (Block block = this; block != null; block = block.getParent()) { - // Find name. - final Symbol symbol = block.symbols.get(name); - // If found then we are good. - if (symbol != null) { - return symbol; - } - } - return null; + public Iterator symbolIterator() { + return symbols.values().iterator(); } /** - * Search for symbol in current function. - * - * @param name Symbol name. - * - * @return Found symbol or null if not found. + * Retrieves an existing symbol defined in the current block. + * @param name the name of the symbol + * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't + * define a symbol with this name. */ - public Symbol findLocalSymbol(final String name) { - // Search up block chain to locate symbol. - for (Block block = this; block != null; block = block.getParent()) { - // Find name. - final Symbol symbol = block.symbols.get(name); - // If found then we are good. - if (symbol != null) { - return symbol; - } - - // If searched function then we are done. - if (block == block.function) { - break; - } - } - - // Not found. - return null; + public Symbol getExistingSymbol(final String name) { + return symbols.get(name); } /** @@ -331,122 +188,6 @@ return statements.size() == 1 && statements.get(0) instanceof CatchNode; } - /** - * Test to see if a symbol is local to the function. - * - * @param symbol Symbol to test. - * @return True if a local symbol. - */ - public boolean isLocal(final Symbol symbol) { - // some temp symbols have no block, so can be assumed local - final Block block = symbol.getBlock(); - return block == null || block.getFunction() == function; - } - - /** - * Declare the definition of a new symbol. - * - * @param name Name of symbol. - * @param symbolFlags Symbol flags. - * @param node Defining Node. - * - * @return Symbol for given name or null for redefinition. - */ - public Symbol defineSymbol(final String name, final int symbolFlags, final Node node) { - int flags = symbolFlags; - Symbol symbol = findSymbol(name); // Locate symbol. - - if ((flags & KINDMASK) == IS_GLOBAL) { - flags |= IS_SCOPE; - } - - if (symbol != null) { - // Symbol was already defined. Check if it needs to be redefined. - if ((flags & KINDMASK) == IS_PARAM) { - if (!function.isLocal(symbol)) { - // Not defined in this function. Create a new definition. - symbol = null; - } else if (symbol.isParam()) { - // Duplicate parameter. Null return will force an error. - assert false : "duplicate parameter"; - return null; - } - } else if ((flags & KINDMASK) == IS_VAR) { - if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & Symbol.IS_LET) == Symbol.IS_LET) { - assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == this) : "duplicate let variable in block"; - // Always create a new definition. - symbol = null; - } else { - // Not defined in this function. Create a new definition. - if (!function.isLocal(symbol) || symbol.less(IS_VAR)) { - symbol = null; - } - } - } - } - - if (symbol == null) { - // If not found, then create a new one. - Block symbolBlock; - - // Determine where to create it. - if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) { - symbolBlock = this; - } else { - symbolBlock = getFunction(); - } - - // Create and add to appropriate block. - symbol = new Symbol(name, flags, node, symbolBlock); - symbolBlock.putSymbol(name, symbol); - - if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { - symbolBlock.getFrame().addSymbol(symbol); - symbol.setNeedsSlot(true); - } - } else if (symbol.less(flags)) { - symbol.setFlags(flags); - } - - if (node != null) { - node.setSymbol(symbol); - } - - return symbol; - } - - /** - * Declare the use of a symbol. - * - * @param name Name of symbol. - * @param node Using node - * - * @return Symbol for given name. - */ - public Symbol useSymbol(final String name, final Node node) { - Symbol symbol = findSymbol(name); - - if (symbol == null) { - // If not found, declare as a free var. - symbol = defineSymbol(name, IS_GLOBAL, node); - } else { - node.setSymbol(symbol); - } - - return symbol; - } - - /** - * Add parent name to the builder. - * - * @param sb String bulder. - */ - public void addParentName(final StringBuilder sb) { - if (parent != null) { - parent.addParentName(sb); - } - } - @Override public void toString(final StringBuilder sb) { for (final Node statement : statements) { @@ -505,16 +246,6 @@ } /** - * Get the FunctionNode for this block, i.e. the function it - * belongs to - * - * @return the function node - */ - public FunctionNode getFunction() { - return function; - } - - /** * Reset the frame for this block * * @param frame the new frame @@ -524,24 +255,6 @@ } /** - * Get the parent block - * - * @return parent block, or null if none exists - */ - public Block getParent() { - return parent; - } - - /** - * Set the parent block - * - * @param parent the new parent block - */ - public void setParent(final Block parent) { - this.parent = parent; - } - - /** * Get the list of statements in this block * * @return a list of statements @@ -551,6 +264,15 @@ } /** + * Applies the specified visitor to all statements in the block. + * @param visitor the visitor. + */ + public void visitStatements(NodeVisitor visitor) { + for (ListIterator stmts = statements.listIterator(); stmts.hasNext();) { + stmts.set(stmts.next().accept(visitor)); + } + } + /** * Reset the statement list for this block * * @param statements new statement list @@ -585,4 +307,29 @@ needsScope = true; } + /** + * Marks this block as using a specified scoped symbol. The block and its parent blocks up to but not + * including the block defining the symbol will be marked as needing parent scope. The block defining the symbol + * will be marked as one that needs to have its own scope. + * @param symbol the symbol being used. + * @param ancestors the iterator over block's containing lexical context + */ + public void setUsesScopeSymbol(final Symbol symbol, Iterator ancestors) { + if(symbol.getBlock() == this) { + setNeedsScope(); + } else { + setUsesParentScopeSymbol(symbol, ancestors); + } + } + + /** + * Invoked when this block uses a scope symbol defined in one of its ancestors. + * @param symbol the scope symbol being used + * @param ancestors iterator over ancestor blocks + */ + void setUsesParentScopeSymbol(final Symbol symbol, Iterator ancestors) { + if(ancestors.hasNext()) { + ancestors.next().setUsesScopeSymbol(symbol, ancestors); + } + } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/BreakNode.java --- a/src/jdk/nashorn/internal/ir/BreakNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/BreakNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -64,8 +64,8 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - return visitor.leave(this); + if (visitor.enterBreakNode(this) != null) { + return visitor.leaveBreakNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/CallNode.java --- a/src/jdk/nashorn/internal/ir/CallNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/CallNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -37,7 +37,7 @@ * IR representation for a function call. * */ -public class CallNode extends Node implements TypeOverride { +public class CallNode extends Node implements TypeOverride { private Type type; @@ -176,13 +176,13 @@ if (hasCallSiteType()) { return type; } - assert !function.getType().isUnknown(); - return function.getType(); + return function instanceof FunctionNode ? ((FunctionNode)function).getReturnType() : Type.OBJECT; } @Override - public void setType(final Type type) { + public CallNode setType(final Type type) { this.type = type; + return this; } private boolean hasCallSiteType() { @@ -208,14 +208,14 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterCallNode(this) != null) { function = function.accept(visitor); for (int i = 0, count = args.size(); i < count; i++) { args.set(i, args.get(i).accept(visitor)); } - return visitor.leave(this); + return visitor.leaveCallNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/CaseNode.java --- a/src/jdk/nashorn/internal/ir/CaseNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/CaseNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -79,7 +79,7 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterCaseNode(this) != null) { if (test != null) { test = test.accept(visitor); } @@ -87,7 +87,7 @@ body = (Block)body.accept(visitor); } - return visitor.leave(this); + return visitor.leaveCaseNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/CatchNode.java --- a/src/jdk/nashorn/internal/ir/CatchNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/CatchNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -84,7 +84,7 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterCatchNode(this) != null) { exception = (IdentNode)exception.accept(visitor); if (exceptionCondition != null) { @@ -92,7 +92,7 @@ } body = (Block)body.accept(visitor); - return visitor.leave(this); + return visitor.leaveCatchNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/ContinueNode.java --- a/src/jdk/nashorn/internal/ir/ContinueNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/ContinueNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -61,8 +61,8 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - return visitor.leave(this); + if (visitor.enterContinueNode(this) != null) { + return visitor.leaveContinueNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/DoWhileNode.java --- a/src/jdk/nashorn/internal/ir/DoWhileNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/DoWhileNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -63,11 +63,11 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterDoWhileNode(this) != null) { body = (Block)body.accept(visitor); test = test.accept(visitor); - return visitor.leave(this); + return visitor.leaveDoWhileNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/EmptyNode.java --- a/src/jdk/nashorn/internal/ir/EmptyNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/EmptyNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -57,8 +57,8 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - return visitor.leave(this); + if (visitor.enterEmptyNode(this) != null) { + return visitor.leaveEmptyNode(this); } return this; } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/ExecuteNode.java --- a/src/jdk/nashorn/internal/ir/ExecuteNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/ExecuteNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -85,9 +85,9 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterExecuteNode(this) != null) { setExpression(expression.accept(visitor)); - return visitor.leave(this); + return visitor.leaveExecuteNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/ForNode.java --- a/src/jdk/nashorn/internal/ir/ForNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/ForNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -76,7 +76,7 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterForNode(this) != null) { if (init != null) { init = init.accept(visitor); } @@ -91,7 +91,7 @@ body = (Block)body.accept(visitor); - return visitor.leave(this); + return visitor.leaveForNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/FunctionNode.java --- a/src/jdk/nashorn/internal/ir/FunctionNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -33,8 +33,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; -import java.util.LinkedList; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Stack; import jdk.nashorn.internal.codegen.CompileUnit; import jdk.nashorn.internal.codegen.Compiler; @@ -45,16 +47,18 @@ import jdk.nashorn.internal.ir.annotations.Ignore; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.parser.Parser; +import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.UserAccessorProperty; import jdk.nashorn.internal.runtime.linker.LinkerCallSite; /** * IR representation for function (or script.) - * */ public class FunctionNode extends Block { + private static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class); + /** Function kinds */ public enum Kind { /** a normal function - nothing special */ @@ -86,7 +90,9 @@ /** method has had its types finalized */ FINALIZED, /** method has been emitted to bytecode */ - EMITTED + EMITTED, + /** code installed in a class loader */ + INSTALLED } /** External function identifier. */ @@ -108,9 +114,6 @@ /** List of parameters. */ private List parameters; - /** List of nested functions. */ - private List functions; - /** First token of function. **/ private long firstToken; @@ -153,10 +156,6 @@ /** Pending control list. */ private final Stack controlStack; - /** Variable declarations in the function's scope */ - @Ignore - private final List declarations; - /** VarNode for this function statement */ @Ignore //this is explicit code anyway and should not be traversed after lower private VarNode funcVarNode; @@ -173,37 +172,42 @@ @Ignore private final EnumSet compilationState; + /** Type hints, e.g based on parameters at call site */ + private final Map specializedTypes; + /** Function flags. */ private int flags; /** Is anonymous function flag. */ - private static final int IS_ANONYMOUS = 0b0000_0000_0000_0001; - /** Is statement flag */ - private static final int IS_STATEMENT = 0b0000_0000_0000_0010; + private static final int IS_ANONYMOUS = 1 << 0; + /** Is the function created in a function declaration (as opposed to a function expression) */ + private static final int IS_DECLARED = 1 << 1; /** is this a strict mode function? */ - private static final int IS_STRICT_MODE = 0b0000_0000_0000_0100; + private static final int IS_STRICT_MODE = 1 << 2; /** Does the function use the "arguments" identifier ? */ - private static final int USES_ARGUMENTS = 0b0000_0000_0000_1000; + private static final int USES_ARGUMENTS = 1 << 3; /** Are we lowered ? */ - private static final int IS_LOWERED = 0b0000_0000_0001_0000; + private static final int IS_LOWERED = 1 << 4; /** Has this node been split because it was too large? */ - private static final int IS_SPLIT = 0b0000_0000_0010_0000; + private static final int IS_SPLIT = 1 << 5; /** Does the function call eval? */ - private static final int HAS_EVAL = 0b0000_0000_0100_0000; + private static final int HAS_EVAL = 1 << 6; /** Does the function contain a with block ? */ - private static final int HAS_WITH = 0b0000_0000_1000_0000; + private static final int HAS_WITH = 1 << 7; /** Does a descendant function contain a with or eval? */ - private static final int HAS_DESCENDANT_WITH_OR_EVAL = 0b0000_0001_0000_0000; + private static final int HAS_DESCENDANT_WITH_OR_EVAL = 1 << 8; /** Does the function define "arguments" identifier as a parameter of nested function name? */ - private static final int DEFINES_ARGUMENTS = 0b0000_0010_0000_0000; + private static final int DEFINES_ARGUMENTS = 1 << 9; /** Does the function need a self symbol? */ - private static final int NEEDS_SELF_SYMBOL = 0b0000_0100_0000_0000; + private static final int NEEDS_SELF_SYMBOL = 1 << 10; /** Does this function or any of its descendants use variables from an ancestor function's scope (incl. globals)? */ - private static final int USES_ANCESTOR_SCOPE = 0b0000_1000_0000_0000; + private static final int USES_ANCESTOR_SCOPE = 1 << 11; /** Is this function lazily compiled? */ - private static final int IS_LAZY = 0b0001_0000_0000_0000; + private static final int IS_LAZY = 1 << 12; /** Does this function have lazy, yet uncompiled children */ - private static final int HAS_LAZY_CHILDREN = 0b0010_0000_0000_0000; + private static final int HAS_LAZY_CHILDREN = 1 << 13; + /** Does this function have lazy, yet uncompiled children */ + private static final int IS_PROGRAM = 1 << 14; /** Does this function or any nested functions contain a with or an eval? */ private static final int HAS_DEEP_WITH_OR_EVAL = HAS_EVAL | HAS_WITH | HAS_DESCENDANT_WITH_OR_EVAL; @@ -211,54 +215,39 @@ private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_WITH_OR_EVAL | IS_SPLIT | HAS_LAZY_CHILDREN; /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */ private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL; - /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep with or eval. */ - private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_WITH_OR_EVAL; + /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep with or eval. + * We also pessimistically need a parent scope if we have lazy children that have not yet been compiled */ + private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_WITH_OR_EVAL | HAS_LAZY_CHILDREN; /** What is the return type of this function? */ private Type returnType = Type.UNKNOWN; /** - * Used to keep track of a function's parent blocks. - * This is needed when a (finally body) block is cloned than contains inner functions. - * Does not include function.getParent(). - */ - @Ignore - private List referencingParentBlocks; - - /** * Constructor * * @param source the source * @param token token * @param finish finish * @param namespace the namespace - * @param parent the parent block * @param ident the identifier * @param name the name of the function */ - @SuppressWarnings("LeakingThisInConstructor") - public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final Block parent, final IdentNode ident, final String name) { - super(source, token, finish, parent, null); + public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final IdentNode ident, final String name) { + super(source, token, finish); this.ident = ident; this.name = name; this.kind = Kind.NORMAL; this.parameters = new ArrayList<>(); - this.functions = new ArrayList<>(); this.firstToken = token; this.lastToken = token; this.namespace = namespace; this.labelStack = new Stack<>(); this.controlStack = new Stack<>(); - this.declarations = new ArrayList<>(); - // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies - // it as such a leak - this is a false positive as we're setting this into a field of the object being - // constructed, so it can't be seen from other threads. - this.function = this; this.compilationState = EnumSet.of(CompilationState.INITIALIZED); + this.specializedTypes = new HashMap<>(); } - @SuppressWarnings("LeakingThisInConstructor") private FunctionNode(final FunctionNode functionNode, final CopyState cs) { super(functionNode, cs); @@ -268,10 +257,9 @@ this.parameters = new ArrayList<>(); for (final IdentNode param : functionNode.getParameters()) { - this.parameters.add((IdentNode) cs.existingOrCopy(param)); + this.parameters.add((IdentNode)cs.existingOrCopy(param)); } - this.functions = new ArrayList<>(); this.firstToken = functionNode.firstToken; this.lastToken = functionNode.lastToken; this.namespace = functionNode.getNamespace(); @@ -283,43 +271,34 @@ this.calleeNode = (IdentNode)cs.existingOrCopy(functionNode.calleeNode); this.labelStack = new Stack<>(); this.controlStack = new Stack<>(); - this.declarations = new ArrayList<>(); - - for (final VarNode decl : functionNode.getDeclarations()) { - declarations.add((VarNode) cs.existingOrCopy(decl)); //TODO same? - } this.flags = functionNode.flags; this.funcVarNode = (VarNode)cs.existingOrCopy(functionNode.funcVarNode); /** VarNode for this function statement */ - // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies - // it as such a leak - this is a false positive as we're setting this into a field of the object being - // constructed, so it can't be seen from other threads. - this.function = this; - this.compilationState = EnumSet.copyOf(functionNode.compilationState); + this.specializedTypes = new HashMap<>(); } @Override protected Node copy(final CopyState cs) { // deep clone all parent blocks - return fixBlockChain(new FunctionNode(this, cs)); + return new FunctionNode(this, cs); } @Override public Node accept(final NodeVisitor visitor) { - final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode(); - final Block saveBlock = visitor.getCurrentBlock(); + final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode(); + final Block saveBlock = visitor.getCurrentBlock(); + final MethodEmitter saveMethodEmitter = visitor.getCurrentMethodEmitter(); + final CompileUnit saveCompileUnit = visitor.getCurrentCompileUnit(); visitor.setCurrentFunctionNode(this); - visitor.setCurrentCompileUnit(getCompileUnit()); - visitor.setCurrentMethodEmitter(getMethodEmitter()); visitor.setCurrentBlock(this); try { - if (visitor.enter(this) != null) { + if (visitor.enterFunctionNode(this) != null) { if (ident != null) { ident = (IdentNode)ident.accept(visitor); } @@ -328,51 +307,25 @@ parameters.set(i, (IdentNode)parameters.get(i).accept(visitor)); } - for (int i = 0, count = functions.size(); i < count; i++) { - functions.set(i, (FunctionNode)functions.get(i).accept(visitor)); - } - for (int i = 0, count = statements.size(); i < count; i++) { statements.set(i, statements.get(i).accept(visitor)); } - return visitor.leave(this); + return visitor.leaveFunctionNode(this); } } finally { visitor.setCurrentBlock(saveBlock); visitor.setCurrentFunctionNode(saveFunctionNode); - visitor.setCurrentCompileUnit(saveFunctionNode != null ? saveFunctionNode.getCompileUnit() : null); - visitor.setCurrentMethodEmitter(saveFunctionNode != null ? saveFunctionNode.getMethodEmitter() : null); + visitor.setCurrentCompileUnit(saveCompileUnit); + visitor.setCurrentMethodEmitter(saveMethodEmitter); } return this; } - /** - * Locate the parent function. - * - * @return Parent function. - */ - public FunctionNode findParentFunction() { - return getParent() != null ? getParent().getFunction() : null; - } - - /** - * Add parent name to the builder. - * - * @param sb String builder. - */ - @Override - public void addParentName(final StringBuilder sb) { - if (!isScript()) { - sb.append(getName()); - sb.append("$"); - } - } - @Override public boolean needsScope() { - return super.needsScope() || isScript(); + return super.needsScope() || isProgram(); } /** @@ -530,12 +483,18 @@ } /** - * Determine if script function. - * - * @return True if script function. + * Returns true if the function is the top-level program. + * @return True if this function node represents the top-level program. */ - public boolean isScript() { - return getParent() == null; + public boolean isProgram() { + return (flags & IS_PROGRAM) != 0; + } + + /** + * Marks the function as representing the top-level program. + */ + public void setProgram() { + flags |= IS_PROGRAM; } /** @@ -575,31 +534,31 @@ /** * Flag this function as using the {@code with} keyword + * @param ancestors the iterator over functions in this functions's containing lexical context */ - public void setHasWith() { + public void setHasWith(final Iterator ancestors) { if(!hasWith()) { this.flags |= HAS_WITH; // with requires scope in parents. // TODO: refine this. with should not force all variables in parents to be in scope, only those that are // actually referenced as identifiers by name - markParentForWithOrEval(); + markParentForWithOrEval(ancestors); } } - private void markParentForWithOrEval() { + private void markParentForWithOrEval(final Iterator ancestors) { // If this is invoked, then either us or a descendant uses with or eval, meaning we must have our own scope. setNeedsScope(); - final FunctionNode parentFunction = findParentFunction(); - if(parentFunction != null) { - parentFunction.setDescendantHasWithOrEval(); + if(ancestors.hasNext()) { + ancestors.next().setDescendantHasWithOrEval(ancestors); } } - private void setDescendantHasWithOrEval() { + private void setDescendantHasWithOrEval(final Iterator ancestors) { if((flags & HAS_DESCENDANT_WITH_OR_EVAL) == 0) { flags |= HAS_DESCENDANT_WITH_OR_EVAL; - markParentForWithOrEval(); + markParentForWithOrEval(ancestors); } } @@ -614,11 +573,12 @@ /** * Flag this function as calling the {@code eval} function + * @param ancestors the iterator over functions in this functions's containing lexical context */ - public void setHasEval() { + public void setHasEval(final Iterator ancestors) { if(!hasEval()) { this.flags |= HAS_EVAL; - markParentForWithOrEval(); + markParentForWithOrEval(ancestors); } } @@ -651,11 +611,34 @@ } /** - * Get all nested functions - * @return list of nested functions in this function + * Returns a list of functions declared by this function. Only includes declared functions, and does not include any + * function expressions that might occur in its body. + * @return a list of functions declared by this function. */ - public List getFunctions() { - return Collections.unmodifiableList(functions); + public List getDeclaredFunctions() { + // Note that the function does not have a dedicated list of declared functions, but rather relies on the + // invariant that all function declarations are at the beginning of the statement list as VarNode with a + // FunctionNode marked as statement with its variable initializer. Every VarNode is also preceded by a + // LineNumberNode. This invariant is established by the parser and has to be preserved in visitors. + final List fns = new ArrayList<>(); + for (final Node stmt : statements) { + if(stmt instanceof LineNumberNode) { + continue; + } else if(stmt instanceof VarNode) { + final Node init = ((VarNode)stmt).getInit(); + if(init instanceof FunctionNode) { + final FunctionNode fn = (FunctionNode)init; + if(fn.isDeclared()) { + fns.add(fn); + continue; + } + } + } + // Node is neither a LineNumberNode, nor a function declaration VarNode. Since all function declarations are + // at the start of the function, we've reached the end of function declarations. + break; + } + return fns; } /** @@ -710,6 +693,7 @@ * Check if this function's generated Java method needs a {@code callee} parameter. Functions that need access to * their parent scope, functions that reference themselves, and non-strict functions that need an Arguments object * (since it exposes {@code arguments.callee} property) will need to have a callee parameter. + * * @return true if the function's generated Java method needs a {@code callee} parameter. */ public boolean needsCallee() { @@ -786,7 +770,7 @@ public boolean needsArguments() { // uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since // for top-level script, "arguments" is picked up from Context by Global.init() instead. - return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isScript(); + return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isProgram(); } /** @@ -805,7 +789,7 @@ * @return true if the function needs parent scope. */ public boolean needsParentScope() { - return (flags & NEEDS_PARENT_SCOPE) != 0 || isScript(); + return (flags & NEEDS_PARENT_SCOPE) != 0 || isProgram(); } /** @@ -865,7 +849,7 @@ * @return true if all variables should be in scope */ public boolean allVarsInScope() { - return isScript() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0; + return isProgram() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0; } /** @@ -919,6 +903,27 @@ } /** + * Get a specialized type for an identity, if one exists + * @param node node to check specialized type for + * @return null if no specialization exists, otherwise type + */ + public Type getSpecializedType(final IdentNode node) { + return specializedTypes.get(node); + } + + /** + * Set parameter type hints for specialization. + * @param types types array of length equal to parameter list size + */ + public void setParameterTypes(final Class[] types) { + assert types.length == parameters.size() : "Type vector length doesn't correspond to parameter types"; + //diff - skip the callee and this etc, they are not explicit params in the parse tree + for (int i = 0; i < types.length ; i++) { + specializedTypes.put(parameters.get(i), Type.typeFor(types[i])); + } + } + + /** * Get the identifier for the variable in which the function return value * should be stored * @return an IdentNode representing the return value @@ -953,19 +958,19 @@ } /** - * Check if this function is a statement - * @return true if function is a statement + * Check if this function is created as a function declaration (as opposed to function expression) + * @return true if function is declared. */ - public boolean isStatement() { - return (flags & IS_STATEMENT) != 0; + public boolean isDeclared() { + return (flags & IS_DECLARED) != 0; } /** - * Flag this function as a statement + * Flag this function as being created as a function declaration (as opposed to a function expression). * @see Parser */ - public void setIsStatement() { - this.flags |= IS_STATEMENT; + public void setIsDeclared() { + this.flags |= IS_DECLARED; } /** @@ -1013,35 +1018,16 @@ } /** - * Marks this function as one using any global symbol. The function and all its parent functions will all be marked - * as needing parent scope. - * @see #needsParentScope() + * Marks this function as using any of its ancestors' scopes. */ - public void setUsesGlobalSymbol() { + public void setUsesAncestorScope() { this.flags |= USES_ANCESTOR_SCOPE; - final FunctionNode parentFn = findParentFunction(); - if(parentFn != null) { - parentFn.setUsesGlobalSymbol(); - } } - /** - * Marks this function as using a specified scoped symbol. The function and its parent functions up to but not - * including the function defining the symbol will be marked as needing parent scope. The function defining the - * symbol will be marked as one that needs to have its own scope. - * @param symbol the symbol being used. - * @see #needsParentScope() - */ - public void setUsesScopeSymbol(final Symbol symbol) { - if(symbol.getBlock() == this) { - setNeedsScope(); - } else { - this.flags |= USES_ANCESTOR_SCOPE; - final FunctionNode parentFn = findParentFunction(); - if(parentFn != null) { - parentFn.setUsesScopeSymbol(symbol); - } - } + @Override + void setUsesParentScopeSymbol(Symbol symbol, Iterator ancestors) { + setUsesAncestorScope(); + super.setUsesParentScopeSymbol(symbol, ancestors); } /** @@ -1116,7 +1102,7 @@ @Override public Type getType() { - return getReturnType(); + return FUNCTION_TYPE; } /** @@ -1176,56 +1162,6 @@ } /** - * Add a new function to the function list. - * - * @param functionNode Function node to add. - */ - @Override - public void addFunction(final FunctionNode functionNode) { - assert functionNode != null; - functions.add(functionNode); - } - - /** - * Add a list of functions to the function list. - * - * @param functionNodes Function nodes to add. - */ - @Override - public void addFunctions(final List functionNodes) { - functions.addAll(functionNodes); - } - - /** - * Set a function list - * - * @param functionNodes to set - */ - @Override - public void setFunctions(final List functionNodes) { - this.functions = functionNodes; - } - - /** - * Add a variable declaration that should be visible to the entire function - * scope. Parser does this. - * - * @param varNode a var node - */ - public void addDeclaration(final VarNode varNode) { - declarations.add(varNode); - } - - /** - * Return all variable declarations from this function scope - * - * @return all VarNodes in scope - */ - public List getDeclarations() { - return Collections.unmodifiableList(declarations); - } - - /** * Get the compile unit used to compile this function * @see Compiler * @return the compile unit @@ -1258,32 +1194,4 @@ public void setMethodEmitter(final MethodEmitter method) { this.method = method; } - - /** - * Each FunctionNode maintains a list of reference to its parent blocks. - * Add a parent block to this function. - * - * @param parentBlock a block to remember as parent - */ - public void addReferencingParentBlock(final Block parentBlock) { - assert parentBlock.getFunction() == function.findParentFunction(); // all parent blocks must be in the same function - if (parentBlock != function.getParent()) { - if (referencingParentBlocks == null) { - referencingParentBlocks = new LinkedList<>(); - } - referencingParentBlocks.add(parentBlock); - } - } - - /** - * Get the known parent blocks to this function - * - * @return list of parent blocks - */ - public List getReferencingParentBlocks() { - if (referencingParentBlocks == null) { - return Collections.emptyList(); - } - return Collections.unmodifiableList(referencingParentBlocks); - } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/IdentNode.java --- a/src/jdk/nashorn/internal/ir/IdentNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/IdentNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -38,18 +38,18 @@ /** * IR representation for an identifier. */ -public class IdentNode extends Node implements PropertyKey, TypeOverride, FunctionCall { +public class IdentNode extends Node implements PropertyKey, TypeOverride, FunctionCall { + private static final int PROPERTY_NAME = 1 << 0; + private static final int INITIALIZED_HERE = 1 << 1; + private static final int FUNCTION = 1 << 2; + /** Identifier. */ private final String name; /** Type for a callsite, e.g. X in a get()X or a set(X)V */ private Type callSiteType; - /** flag for an ident that is the property name of an AccessNode. */ - private boolean isPropertyName; - - /** flag for an ident on the left hand side of var lhs = rhs;. */ - private boolean isInitializedHere; + private byte flags; /** * Constructor @@ -71,9 +71,8 @@ */ public IdentNode(final IdentNode identNode) { super(identNode); - this.name = identNode.getName(); - this.isPropertyName = identNode.isPropertyName; - this.isInitializedHere = identNode.isInitializedHere; + this.name = identNode.getName(); + this.flags = identNode.flags; } @Override @@ -92,12 +91,17 @@ } @Override - public void setType(final Type type) { + public IdentNode setType(final Type type) { if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType()); } - this.callSiteType = type; // do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't + if(this.callSiteType == type) { + return this; + } + final IdentNode n = (IdentNode)clone(); + n.callSiteType = type; + return n; } @Override @@ -131,8 +135,8 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - return visitor.leave(this); + if (visitor.enterIdentNode(this) != null) { + return visitor.leaveIdentNode(this); } return this; @@ -179,14 +183,18 @@ * @return true if this is a property name */ public boolean isPropertyName() { - return isPropertyName; + return (flags & PROPERTY_NAME) != 0; } /** * Flag this IdentNode as a property name + * @return a node equivalent to this one except for the requested change. */ - public void setIsPropertyName() { - isPropertyName = true; + public IdentNode setIsPropertyName() { + if(isPropertyName()) return this; + final IdentNode n = (IdentNode)clone(); + n.flags |= PROPERTY_NAME; + return n; } /** @@ -194,14 +202,18 @@ * @return true if IdentNode is initialized on creation */ public boolean isInitializedHere() { - return isInitializedHere; + return (flags & INITIALIZED_HERE) != 0; } /** * Flag IdentNode to be initialized on creation + * @return a node equivalent to this one except for the requested change. */ - public void setIsInitializedHere() { - isInitializedHere = true; + public IdentNode setIsInitializedHere() { + if(isInitializedHere()) return this; + final IdentNode n = (IdentNode)clone(); + n.flags |= INITIALIZED_HERE; + return n; } /** @@ -216,6 +228,17 @@ @Override public boolean isFunction() { - return false; + return (flags & FUNCTION) != 0; + } + + /** + * Mark this node as being the callee operand of a {@link CallNode}. + * @return an ident node identical to this one in all aspects except with its function flag set. + */ + public IdentNode setIsFunction() { + if(isFunction()) return this; + final IdentNode n = (IdentNode)clone(); + n.flags |= FUNCTION; + return n; } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/IfNode.java --- a/src/jdk/nashorn/internal/ir/IfNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/IfNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -75,7 +75,7 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterIfNode(this) != null) { test = test.accept(visitor); pass = (Block)pass.accept(visitor); @@ -84,7 +84,7 @@ fail = (Block)fail.accept(visitor); } - return visitor.leave(this); + return visitor.leaveIfNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/IndexNode.java --- a/src/jdk/nashorn/internal/ir/IndexNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/IndexNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -36,7 +36,7 @@ * IR representation of an indexed access (brackets operator.) * */ -public class IndexNode extends BaseNode implements TypeOverride { +public class IndexNode extends BaseNode implements TypeOverride { /** Property ident. */ private Node index; @@ -92,10 +92,10 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterIndexNode(this) != null) { base = base.accept(visitor); index = index.accept(visitor); - return visitor.leave(this); + return visitor.leaveIndexNode(this); } return this; @@ -144,12 +144,13 @@ } @Override - public void setType(final Type type) { + public IndexNode setType(final Type type) { if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType()); } hasCallSiteType = true; getSymbol().setTypeOverride(type); + return this; } @Override diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/LabelNode.java --- a/src/jdk/nashorn/internal/ir/LabelNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/LabelNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -81,10 +81,10 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterLabelNode(this) != null) { label = (IdentNode)label.accept(visitor); body = (Block)body.accept(visitor); - return visitor.leave(this); + return visitor.leaveLabelNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/LexicalContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,198 @@ +package jdk.nashorn.internal.ir; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * A class that tracks the current lexical context of node visitation as a stack of {@link Block} nodes. Has special + * methods to retrieve useful subsets of the context. + */ +public class LexicalContext implements Cloneable { + private final Deque lexicalContext; + + /** + * Creates a new empty lexical context. + */ + public LexicalContext() { + lexicalContext = new ArrayDeque<>(); + } + + /** + * Pushes a new block on top of the context, making it the innermost open block. + * @param block the new block + */ + public void push(Block block) { + //new Exception(block.toString()).printStackTrace(); + lexicalContext.push(block); + } + + /** + * Pops the innermost block off the context. + * @param the block expected to be popped, used to detect unbalanced pushes/pops + */ + public void pop(Block block) { + final Block popped = lexicalContext.pop(); + assert popped == block; + } + + /** + * Returns an iterator over all blocks in the context, with the top block (innermost lexical context) first. + * @return an iterator over all blocks in the context. + */ + public Iterator getBlocks() { + return lexicalContext.iterator(); + } + + /** + * Returns an iterator over all functions in the context, with the top (innermost open) function first. + * @return an iterator over all functions in the context. + */ + public Iterator getFunctions() { + return new FunctionIterator(getBlocks()); + } + + private static final class FunctionIterator implements Iterator { + private final Iterator it; + private FunctionNode next; + + FunctionIterator(Iterator it) { + this.it = it; + next = findNext(); + } + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public FunctionNode next() { + if(next == null) { + throw new NoSuchElementException(); + } + FunctionNode lnext = next; + next = findNext(); + return lnext; + } + + private FunctionNode findNext() { + while(it.hasNext()) { + final Block block = it.next(); + if(block instanceof FunctionNode) { + return ((FunctionNode)block); + } + } + return null; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Returns an iterator over all ancestors block of the given block, with its parent block first. + * @param block the block whose ancestors are returned + * @return an iterator over all ancestors block of the given block. + */ + public Iterator getAncestorBlocks(Block block) { + final Iterator it = getBlocks(); + while(it.hasNext()) { + final Block b = it.next(); + if(block == b) { + return it; + } + } + throw new AssertionError("Block is not on the current lexical context stack"); + } + + /** + * Returns an iterator over a block and all its ancestors blocks, with the block first. + * @param block the block that is the starting point of the iteration. + * @return an iterator over a block and all its ancestors. + */ + public Iterator getBlocks(final Block block) { + final Iterator it = getAncestorBlocks(block); + return new Iterator() { + boolean blockReturned = false; + @Override + public boolean hasNext() { + return it.hasNext() || !blockReturned; + } + @Override + public Block next() { + if(blockReturned) { + return it.next(); + } + blockReturned = true; + return block; + } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + /** + * Returns the closest function node to the block. If the block is itself a function, it is returned. + * @param block the block + * @return the function closest to the block. + * @see #getParentFunction(Block) + */ + public FunctionNode getFunction(Block block) { + if(block instanceof FunctionNode) { + return (FunctionNode)block; + } + return getParentFunction(block); + } + + /** + * Returns the closest function node to the block and all its ancestor functions. If the block is itself a function, + * it is returned too. + * @param block the block + * @return the closest function node to the block and all its ancestor functions. + */ + public Iterator getFunctions(final Block block) { + return new FunctionIterator(getBlocks(block)); + } + + /** + * Returns the containing function of the block. If the block is itself a function, its parent function is returned. + * @param block the block + * @return the containing function of the block. + * @see #getFunction(Block) + */ + public FunctionNode getParentFunction(Block block) { + return getFirstFunction(getAncestorBlocks(block)); + } + + private static FunctionNode getFirstFunction(Iterator it) { + while(it.hasNext()) { + final Block ancestor = it.next(); + if(ancestor instanceof FunctionNode) { + return (FunctionNode)ancestor; + } + } + return null; + } + + /** + * Returns the innermost block in the context. + * @return the innermost block in the context. + */ + public Block getCurrentBlock() { + return lexicalContext.element(); + } + + /** + * Returns the innermost function in the context. + * @return the innermost function in the context. + */ + public FunctionNode getCurrentFunction() { + return getFirstFunction(getBlocks()); + } +} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/LineNumberNode.java --- a/src/jdk/nashorn/internal/ir/LineNumberNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/LineNumberNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -63,8 +63,8 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - return visitor.leave(this); + if (visitor.enterLineNumberNode(this) != null) { + return visitor.leaveLineNumberNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/LiteralNode.java --- a/src/jdk/nashorn/internal/ir/LiteralNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -46,7 +46,7 @@ */ public abstract class LiteralNode extends Node implements PropertyKey { /** Literal value */ - protected T value; + protected final T value; /** * Constructor @@ -67,8 +67,17 @@ * @param literalNode source node */ protected LiteralNode(final LiteralNode literalNode) { + this(literalNode, literalNode.value); + } + + /** + * A copy constructor with value change. + * @param literalNode the original literal node + * @param newValue new value for this node + */ + protected LiteralNode(final LiteralNode literalNode, final T newValue) { super(literalNode); - this.value = literalNode.value; + this.value = newValue; } @Override @@ -217,8 +226,8 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - return visitor.leave(this); + if (visitor.enterLiteralNode(this) != null) { + return visitor.leaveLiteralNode(this); } return this; @@ -544,6 +553,10 @@ super(literalNode); } + private NodeLiteralNode(final LiteralNode literalNode, final Node value) { + super(literalNode, value); + } + @Override protected Node copy(final CopyState cs) { return new NodeLiteralNode(this); @@ -551,11 +564,14 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterLiteralNode(this) != null) { if (value != null) { - value = value.accept(visitor); + final Node newValue = value.accept(visitor); + if(value != newValue) { + return visitor.leaveLiteralNode(new NodeLiteralNode(this, newValue)); + } } - return visitor.leave(this); + return visitor.leaveLiteralNode(this); } return this; @@ -878,14 +894,14 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterLiteralNode(this) != null) { for (int i = 0; i < value.length; i++) { final Node element = value[i]; if (element != null) { value[i] = element.accept(visitor); } } - return visitor.leave(this); + return visitor.leaveLiteralNode(this); } return this; } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/Location.java --- a/src/jdk/nashorn/internal/ir/Location.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/Location.java Tue Mar 26 12:08:00 2013 -0700 @@ -65,7 +65,11 @@ @Override protected Object clone() { - return new Location(this); + try { + return super.clone(); + } catch(CloneNotSupportedException e) { + throw new AssertionError(e); + } } @Override diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/Node.java --- a/src/jdk/nashorn/internal/ir/Node.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/Node.java Tue Mar 26 12:08:00 2013 -0700 @@ -165,12 +165,19 @@ return true; } - setIsResolved(); + setIsResolved(true); return false; } /** + * Reset the resolved flag. + */ + public void resetResolved() { + setIsResolved(false); + } + + /** * Is this a debug info node like LineNumberNode etc? * * @return true if this is a debug node @@ -234,8 +241,7 @@ * * @return Deep copy of the Node. */ - @Override - public final Node clone() { + public final Node copy() { return copy(new CopyState()); } @@ -349,10 +355,10 @@ } /** - * Flag this node as resolved, i.e. code has been generated for it + * Flag this node as resolved or not, i.e. code has been generated for it */ - public void setIsResolved() { - this.isResolved = true; + private void setIsResolved(boolean isResolved) { + this.isResolved = isResolved; } /** diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/ObjectNode.java --- a/src/jdk/nashorn/internal/ir/ObjectNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/ObjectNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import jdk.nashorn.internal.ir.annotations.Ignore; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.runtime.Source; @@ -36,9 +35,6 @@ * IR representation of an object literal. */ public class ObjectNode extends Node { - /** Literal context. */ - @Ignore - private Block context; /** Literal elements. */ private final List elements; @@ -49,13 +45,11 @@ * @param source the source * @param token token * @param finish finish - * @param context the block for this ObjectNode * @param elements the elements used to initialize this ObjectNode */ - public ObjectNode(final Source source, final long token, final int finish, final Block context, final List elements) { + public ObjectNode(final Source source, final long token, final int finish, final List elements) { super(source, token, finish); - this.context = context; this.elements = elements; } @@ -68,7 +62,6 @@ newElements.add(cs.existingOrCopy(element)); } - this.context = (Block)cs.existingOrCopy(objectNode.context); this.elements = newElements; } @@ -79,16 +72,12 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - if (context != null) { - context = (Block)context.accept(visitor); - } - + if (visitor.enterObjectNode(this) != null) { for (int i = 0, count = elements.size(); i < count; i++) { elements.set(i, elements.get(i).accept(visitor)); } - return visitor.leave(this); + return visitor.leaveObjectNode(this); } return this; @@ -117,14 +106,6 @@ } /** - * Get the block that is this ObjectNode's literal context - * @return the block - */ - public Block getContext() { - return context; - } - - /** * Get the elements of this literal node * @return a list of elements */ diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/PropertyNode.java --- a/src/jdk/nashorn/internal/ir/PropertyNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/PropertyNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -88,7 +88,7 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterPropertyNode(this) != null) { key = (PropertyKey)((Node)key).accept(visitor); if (value != null) { @@ -103,7 +103,7 @@ setter = setter.accept(visitor); } - return visitor.leave(this); + return visitor.leavePropertyNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/ReferenceNode.java --- a/src/jdk/nashorn/internal/ir/ReferenceNode.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.ir; - -import jdk.nashorn.internal.ir.annotations.Reference; -import jdk.nashorn.internal.ir.visitor.NodeVisitor; -import jdk.nashorn.internal.runtime.Source; - -/** - * IR representation of a reference to another entity (function.) - */ -public class ReferenceNode extends Node { - /** Node referenced. */ - @Reference - private final FunctionNode reference; - - /** - * Constructor - * - * @param source the source - * @param token token - * @param finish finish - * @param reference the function node to reference - */ - public ReferenceNode(final Source source, final long token, final int finish, final FunctionNode reference) { - super(source, token, finish); - - this.reference = reference; - } - - private ReferenceNode(final ReferenceNode referenceNode) { - super(referenceNode); - - this.reference = referenceNode.reference; - } - - @Override - protected Node copy(final CopyState cs) { - return new ReferenceNode(this); - } - - @Override - public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - return visitor.leave(this); - } - - return this; - } - - @Override - public void toString(final StringBuilder sb) { - if (reference == null) { - sb.append("null"); - } else { - reference.toString(sb); - } - } - - /** - * Get there function node reference that this node points tp - * @return a function node reference - */ - public FunctionNode getReference() { - return reference; - } - -} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/ReturnNode.java --- a/src/jdk/nashorn/internal/ir/ReturnNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/ReturnNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -100,12 +100,12 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterReturnNode(this) != null) { if (expression != null) { expression = expression.accept(visitor); } - return visitor.leave(this); + return visitor.leaveReturnNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/RuntimeNode.java --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -38,7 +38,7 @@ * IR representation for a runtime call. * */ -public class RuntimeNode extends Node implements TypeOverride { +public class RuntimeNode extends Node implements TypeOverride { /** * Request enum used for meta-information about the runtime request @@ -393,8 +393,9 @@ } @Override - public void setType(final Type type) { + public RuntimeNode setType(final Type type) { this.callSiteType = type; + return this; } @Override @@ -408,12 +409,12 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterRuntimeNode(this) != null) { for (int i = 0, count = args.size(); i < count; i++) { args.set(i, args.get(i).accept(visitor)); } - return visitor.leave(this); + return visitor.leaveRuntimeNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/SplitNode.java --- a/src/jdk/nashorn/internal/ir/SplitNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/SplitNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -108,10 +108,10 @@ visitor.setCurrentMethodEmitter(getMethodEmitter()); try { - if (visitor.enter(this) != null) { + if (visitor.enterSplitNode(this) != null) { body = body.accept(visitor); - return visitor.leave(this); + return visitor.leaveSplitNode(this); } } finally { visitor.setCurrentCompileUnit(saveCompileUnit); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/SwitchNode.java --- a/src/jdk/nashorn/internal/ir/SwitchNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/SwitchNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -85,7 +85,7 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterSwitchNode(this) != null) { expression = expression.accept(visitor); for (int i = 0, count = cases.size(); i < count; i++) { @@ -94,7 +94,7 @@ //the default case is in the cases list and should not be explicitly traversed! - return visitor.leave(this); + return visitor.leaveSwitchNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/Symbol.java --- a/src/jdk/nashorn/internal/ir/Symbol.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/Symbol.java Tue Mar 26 12:08:00 2013 -0700 @@ -38,31 +38,31 @@ */ public final class Symbol implements Comparable { - /** Symbol flags. Kind ordered by precedence. */ - public static final int IS_TEMP = 0b0000_0001; + /** Symbol kinds. Kind ordered by precedence. */ + public static final int IS_TEMP = 1; /** Is this Global */ - public static final int IS_GLOBAL = 0b0000_0010; + public static final int IS_GLOBAL = 2; /** Is this a variable */ - public static final int IS_VAR = 0b0000_0011; + public static final int IS_VAR = 3; /** Is this a parameter */ - public static final int IS_PARAM = 0b0000_0100; + public static final int IS_PARAM = 4; /** Is this a constant */ - public static final int IS_CONSTANT = 0b0000_0101; - - static final int KINDMASK = 0b0000_1111; + public static final int IS_CONSTANT = 5; + /** Mask for kind flags */ + public static final int KINDMASK = (1 << 3) - 1; // Kinds are represented by lower three bits /** Is this scope */ - public static final int IS_SCOPE = 0b0000_0001_0000; + public static final int IS_SCOPE = 1 << 4; /** Is this a this symbol */ - public static final int IS_THIS = 0b0000_0010_0000; + public static final int IS_THIS = 1 << 5; /** Can this symbol ever be undefined */ - public static final int CAN_BE_UNDEFINED = 0b0000_0100_0000; + public static final int CAN_BE_UNDEFINED = 1 << 6; /** Can this symbol ever have primitive types */ - public static final int CAN_BE_PRIMITIVE = 0b0000_1000_0000; + public static final int CAN_BE_PRIMITIVE = 1 << 7; /** Is this a let */ - public static final int IS_LET = 0b0001_0000_0000; + public static final int IS_LET = 1 << 8; /** Is this an internal symbol, never represented explicitly in source code */ - public static final int IS_INTERNAL = 0b0010_0000_0000; + public static final int IS_INTERNAL = 1 << 9; /** Null or name identifying symbol. */ private final String name; @@ -269,15 +269,6 @@ return type.isCategory2() ? 2 : 1; } - /** - * Return the defining function (scope.) - * - * @return Defining function. - */ - public FunctionNode findFunction() { - return block != null ? block.getFunction() : null; - } - @Override public boolean equals(final Object other) { if (!(other instanceof Symbol)) { @@ -487,27 +478,6 @@ } /** - * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load - * - * @param currentFunction function to check for fast scope - * @return true if fast scope - */ - public boolean isFastScope(final FunctionNode currentFunction) { - if (!isScope() || !block.needsScope()) { - return false; - } - // Allow fast scope access if no parent function contains with or eval - FunctionNode func = currentFunction; - while (func != null) { - if (func.hasWith() || func.hasEval()) { - return false; - } - func = func.findParentFunction(); - } - return true; - } - - /** * Get the block in which the symbol is defined * @return a block */ @@ -651,7 +621,7 @@ * @return true if this this is a global scope symbol */ public boolean isTopLevel() { - return block instanceof FunctionNode && ((FunctionNode) block).isScript(); + return block instanceof FunctionNode && ((FunctionNode) block).isProgram(); } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/TernaryNode.java --- a/src/jdk/nashorn/internal/ir/TernaryNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/TernaryNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -77,11 +77,11 @@ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - lhs = lhs.accept(visitor); - rhs = rhs.accept(visitor); - third = third.accept(visitor); - return visitor.leave(this); + if (visitor.enterTernaryNode(this) != null) { + final Node newLhs = lhs().accept(visitor); + final Node newRhs = rhs().accept(visitor); + final Node newThird = third.accept(visitor); + return visitor.leaveTernaryNode((TernaryNode)setThird(newThird).setLHS(newLhs).setRHS(newRhs)); } return this; @@ -133,8 +133,12 @@ /** * Reset the "third" node for this ternary expression, i.e. "z" in x ? y : z * @param third a node + * @return a node equivalent to this one except for the requested change. */ - public void setThird(final Node third) { - this.third = third; + public TernaryNode setThird(final Node third) { + if(this.third == third) return this; + final TernaryNode n = (TernaryNode)clone(); + n.third = third; + return n; } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/ThrowNode.java --- a/src/jdk/nashorn/internal/ir/ThrowNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/ThrowNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -75,9 +75,9 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterThrowNode(this) != null) { setExpression(expression.accept(visitor)); - return visitor.leave(this); + return visitor.leaveThrowNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/TryNode.java --- a/src/jdk/nashorn/internal/ir/TryNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/TryNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -101,7 +101,7 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterTryNode(this) != null) { // Need to do first for termination analysis. if (finallyBody != null) { finallyBody = (Block)finallyBody.accept(visitor); @@ -115,7 +115,7 @@ } this.catchBlocks = newCatchBlocks; - return visitor.leave(this); + return visitor.leaveTryNode(this); } return this; @@ -155,6 +155,15 @@ } /** + * Returns true if the specified block is the body of this try block, or any of its catch blocks. + * @param block the block + * @return true if the specified block is the body of this try block, or any of its catch blocks. + */ + public boolean isChildBlock(Block block) { + return body == block || catchBlocks.contains(block); + } + + /** * Get the catch blocks for this try block * @return a list of blocks */ diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/TypeOverride.java --- a/src/jdk/nashorn/internal/ir/TypeOverride.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/TypeOverride.java Tue Mar 26 12:08:00 2013 -0700 @@ -36,15 +36,17 @@ * by using JSType.toInt32. Especially in scenarios where the field is already stored * as a primitive, this will be much faster than the "object is all I see" scope * available in the method + * @param the type of the node implementing the interface */ -public interface TypeOverride { +public interface TypeOverride { /** * Set the override type * * @param type the type + * @return a node equivalent to this one except for the requested change. */ - public void setType(final Type type); + public T setType(final Type type); /** * Returns true if this node can have a callsite override, e.g. all scope ident nodes diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/UnaryNode.java --- a/src/jdk/nashorn/internal/ir/UnaryNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -41,7 +41,7 @@ */ public class UnaryNode extends Node implements Assignment { /** Right hand side argument. */ - protected Node rhs; + private Node rhs; /** * Constructor @@ -104,6 +104,11 @@ } @Override + public Node setAssignmentDest(Node n) { + return setRHS(n); + } + + @Override public Node getAssignmentSource() { return getAssignmentDest(); } @@ -132,9 +137,8 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - rhs = rhs.accept(visitor); - return visitor.leave(this); + if (visitor.enterUnaryNode(this) != null) { + return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor))); } return this; @@ -152,9 +156,9 @@ if (isConvert) { convertPos = sb.length(); - sb.append("(("); + sb.append("("); sb.append(getType()); - sb.append(")"); + sb.append(")("); } if (!isPostfix && !isConvert) { @@ -191,8 +195,6 @@ sb.setCharAt(convertPos, ' '); } } - - //TODO - conversions still have too many parenthesis - makes --print-lower-parse hard to read } /** @@ -214,10 +216,12 @@ * @see BinaryNode * * @param rhs right hand side or expression node + * @return a node equivalent to this one except for the requested change. */ - public void setRHS(final Node rhs) { - this.rhs = rhs; + public UnaryNode setRHS(final Node rhs) { + if(this.rhs == rhs) return this; + final UnaryNode n = (UnaryNode)clone(); + n.rhs = rhs; + return n; } - - } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/VarNode.java --- a/src/jdk/nashorn/internal/ir/VarNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/VarNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -38,8 +38,8 @@ /** Initialization expression. */ private Node init; - /** Is this a function var node */ - private boolean isFunctionVarNode; + /** Is this a var statement (as opposed to a "var" in a for loop statement) */ + private final boolean isStatement; /** * Constructor @@ -51,20 +51,34 @@ * @param init init node or null if just a declaration */ public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) { + this(source, token, finish, name, init, true); + } + + /** + * Constructor + * + * @param source the source + * @param token token + * @param finish finish + * @param name name of variable + * @param init init node or null if just a declaration + * @param isStatement if this is a var statement (true), or a for-loop initializer (false) + */ + public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, boolean isStatement) { super(source, token, finish); - this.name = name; + this.name = init == null ? name : name.setIsInitializedHere(); this.init = init; - if (init != null) { - this.name.setIsInitializedHere(); - } + this.isStatement = isStatement; } + private VarNode(final VarNode varNode, final CopyState cs) { super(varNode); this.name = (IdentNode)cs.existingOrCopy(varNode.name); this.init = cs.existingOrCopy(varNode.init); + this.isStatement = varNode.isStatement; } @Override @@ -83,6 +97,11 @@ } @Override + public Node setAssignmentDest(IdentNode n) { + return setName(n); + } + + @Override public Node getAssignmentSource() { return isAssignment() ? getInit() : null; } @@ -127,16 +146,19 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { - name = (IdentNode)name.accept(visitor); - - if (init != null) { - init = init.accept(visitor); + if (visitor.enterVarNode(this) != null) { + final IdentNode newName = (IdentNode)name.accept(visitor); + final Node newInit = init == null ? null : init.accept(visitor); + final VarNode newThis; + if(name != newName || init != newInit) { + newThis = (VarNode)clone(); + newThis.init = newInit; + newThis.name = newInit == null ? newName : newName.setIsInitializedHere(); + } else { + newThis = this; } - - return visitor.leave(this); + return visitor.leaveVarNode(newThis); } - return this; } @@ -162,9 +184,13 @@ /** * Reset the initialization expression * @param init new initialization expression + * @return a node equivalent to this one except for the requested change. */ - public void setInit(final Node init) { - this.init = init; + public VarNode setInit(final Node init) { + if(this.init == init) return this; + final VarNode n = (VarNode)clone(); + n.init = init; + return n; } /** @@ -179,30 +205,26 @@ * Reset the identifier for this VarNode * @param name new IdentNode representing the variable being set or declared */ - public void setName(final IdentNode name) { - this.name = name; + private VarNode setName(final IdentNode name) { + if(this.name == name) return this; + final VarNode n = (VarNode)clone(); + n.name = name; + return n; } /** - * Check if this is a virtual assignment of a function node. Function nodes declared - * with a name are hoisted to the top of the scope and appear as symbols too. This is - * implemented by representing them as virtual VarNode assignments added to the code - * during lowering - * - * @see FunctionNode - * - * @return true if this is a virtual function declaration + * Returns true if this is a var statement (as opposed to a var initializer in a for loop). + * @return true if this is a var statement (as opposed to a var initializer in a for loop). */ - public boolean isFunctionVarNode() { - return isFunctionVarNode; + public boolean isStatement() { + return isStatement; } /** - * Flag this var node as a virtual function var node assignment as described in - * {@link VarNode#isFunctionVarNode()} + * Returns true if this is a function declaration. + * @return true if this is a function declaration. */ - public void setIsFunctionVarNode() { - this.isFunctionVarNode = true; + public boolean isFunctionDeclaration() { + return init instanceof FunctionNode && ((FunctionNode)init).isDeclared(); } - } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/WhileNode.java --- a/src/jdk/nashorn/internal/ir/WhileNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/WhileNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -88,11 +88,11 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterWhileNode(this) != null) { test = test.accept(visitor); body = (Block)body.accept(visitor); - return visitor.leave(this); + return visitor.leaveWhileNode(this); } return this; } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/WithNode.java --- a/src/jdk/nashorn/internal/ir/WithNode.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/WithNode.java Tue Mar 26 12:08:00 2013 -0700 @@ -73,10 +73,10 @@ */ @Override public Node accept(final NodeVisitor visitor) { - if (visitor.enter(this) != null) { + if (visitor.enterWithNode(this) != null) { expression = expression.accept(visitor); body = (Block)body.accept(visitor); - return visitor.leave(this); + return visitor.leaveWithNode(this); } return this; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/annotations/ChildNode.java --- a/src/jdk/nashorn/internal/ir/annotations/ChildNode.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.ir.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * This is a child node, a real node, not a reference, to an IR node that should - * be traversed. - *

- * TODO Currently not in use. Would make e.g. accept methods simple and unified - * @see jdk.nashorn.internal.ir.Node - */ -@Retention(value=RetentionPolicy.RUNTIME) -public @interface ChildNode { - /** order of traversal compared to other children */ - public int order() default -1; -} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/annotations/ParentNode.java --- a/src/jdk/nashorn/internal/ir/annotations/ParentNode.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.ir.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Signifies a parent of a node, i.e. node that should not be traversed if we - * go down the AST. In automatic parsing this can be handled by @Reference - * annotations instead, as all parents are references. - *

- * TODO The use case is automating and creating one implementation of something like - * Node.getParent() - * - * @see jdk.nashorn.internal.ir.Node - */ -@Retention(value=RetentionPolicy.RUNTIME) -public @interface ParentNode { - // EMPTY -} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/annotations/Reference.java --- a/src/jdk/nashorn/internal/ir/annotations/Reference.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/annotations/Reference.java Tue Mar 26 12:08:00 2013 -0700 @@ -33,7 +33,6 @@ * AST traversal and cloning. Cloning currently as a rule uses * existingOrSame for references and otherwise existingOrCopy *

- * TODO this could probably be automated using the @Reference annotation. */ @Retention(value=RetentionPolicy.RUNTIME) diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/debug/ASTWriter.java --- a/src/jdk/nashorn/internal/ir/debug/ASTWriter.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/debug/ASTWriter.java Tue Mar 26 12:08:00 2013 -0700 @@ -27,6 +27,7 @@ import java.lang.reflect.Field; import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Collection; import java.util.Deque; import java.util.Iterator; @@ -36,10 +37,10 @@ import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.TernaryNode; import jdk.nashorn.internal.ir.annotations.Ignore; -import jdk.nashorn.internal.ir.annotations.ParentNode; import jdk.nashorn.internal.ir.annotations.Reference; import jdk.nashorn.internal.parser.Token; import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.Debug; /** * AST-as-text visualizer. Sometimes you want tree form and not source @@ -47,7 +48,6 @@ * * see the flags --print-ast and --print-ast-lower */ - public final class ASTWriter { /** Root node from which to start the traversal */ private final Node root; @@ -71,12 +71,22 @@ @Override public String toString() { final StringBuilder sb = new StringBuilder(); - printAST(sb, null, "root", root, 0); + printAST(sb, null, null, "root", root, 0); return sb.toString(); } + /** + * Return the visited nodes in an ordered list + * @return the list of nodes in order + */ + public Node[] toArray() { + final List preorder = new ArrayList<>(); + printAST(new StringBuilder(), preorder, null, "root", root, 0); + return preorder.toArray(new Node[preorder.size()]); + } + @SuppressWarnings("unchecked") - private void printAST(final StringBuilder sb, final Field field, final String name, final Node node, final int indent) { + private void printAST(final StringBuilder sb, final List preorder, final Field field, final String name, final Node node, final int indent) { ASTWriter.indent(sb, indent); if (node == null) { sb.append("[Object "); @@ -85,13 +95,23 @@ return; } + if (preorder != null) { + preorder.add(node); + } + final boolean isReference = field != null && field.getAnnotation(Reference.class) != null; Class clazz = node.getClass(); String type = clazz.getName(); type = type.substring(type.lastIndexOf('.') + 1, type.length()); -// type += "@" + Debug.id(node) + "#" + node.getSymbol(); + if (isReference) { + type = "ref: " + type; + } + type += "@" + Debug.id(node); + if (node.getSymbol() != null) { + type += "#" + node.getSymbol(); + } final List children = new LinkedList<>(); @@ -153,9 +173,7 @@ append('\n'); for (final Field child : children) { - if (child.getAnnotation(ParentNode.class) != null) { - continue; - } else if (child.getAnnotation(Ignore.class) != null) { + if (child.getAnnotation(Ignore.class) != null) { continue; } @@ -168,7 +186,7 @@ } if (value instanceof Node) { - printAST(sb, child, child.getName(), (Node)value, indent + 1); + printAST(sb, preorder, child, child.getName(), (Node)value, indent + 1); } else if (value instanceof Collection) { int pos = 0; ASTWriter.indent(sb, indent + 1); @@ -180,7 +198,7 @@ append('\n'); for (final Node member : (Collection)value) { - printAST(sb, child, child.getName() + "[" + pos++ + "]", member, indent + 2); + printAST(sb, preorder, child, child.getName() + "[" + pos++ + "]", member, indent + 2); } } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/debug/JSONWriter.java --- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Tue Mar 26 12:08:00 2013 -0700 @@ -112,7 +112,7 @@ } @Override - public Node enter(final AccessNode accessNode) { + public Node enterAccessNode(final AccessNode accessNode) { enterDefault(accessNode); type("MemberExpression"); @@ -132,7 +132,7 @@ } @Override - public Node enter(final Block block) { + public Node enterBlock(final Block block) { enterDefault(block); type("BlockStatement"); @@ -154,7 +154,7 @@ } @Override - public Node enter(final BinaryNode binaryNode) { + public Node enterBinaryNode(final BinaryNode binaryNode) { enterDefault(binaryNode); final String name; @@ -183,7 +183,7 @@ } @Override - public Node enter(final BreakNode breakNode) { + public Node enterBreakNode(final BreakNode breakNode) { enterDefault(breakNode); type("BreakStatement"); @@ -201,7 +201,7 @@ } @Override - public Node enter(final CallNode callNode) { + public Node enterCallNode(final CallNode callNode) { enterDefault(callNode); type("CallExpression"); @@ -217,7 +217,7 @@ } @Override - public Node enter(final CaseNode caseNode) { + public Node enterCaseNode(final CaseNode caseNode) { enterDefault(caseNode); type("SwitchCase"); @@ -238,7 +238,7 @@ } @Override - public Node enter(final CatchNode catchNode) { + public Node enterCatchNode(final CatchNode catchNode) { enterDefault(catchNode); type("CatchClause"); @@ -264,7 +264,7 @@ } @Override - public Node enter(final ContinueNode continueNode) { + public Node enterContinueNode(final ContinueNode continueNode) { enterDefault(continueNode); type("ContinueStatement"); @@ -282,7 +282,7 @@ } @Override - public Node enter(final DoWhileNode doWhileNode) { + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { enterDefault(doWhileNode); type("DoWhileStatement"); @@ -299,7 +299,7 @@ } @Override - public Node enter(final EmptyNode emptyNode) { + public Node enterEmptyNode(final EmptyNode emptyNode) { enterDefault(emptyNode); type("EmptyStatement"); @@ -308,7 +308,7 @@ } @Override - public Node enter(final ExecuteNode executeNode) { + public Node enterExecuteNode(final ExecuteNode executeNode) { enterDefault(executeNode); type("ExpressionStatement"); @@ -321,7 +321,7 @@ } @Override - public Node enter(final ForNode forNode) { + public Node enterForNode(final ForNode forNode) { enterDefault(forNode); if (forNode.isForIn() || (forNode.isForEach() && forNode.getInit() != null)) { @@ -384,14 +384,14 @@ } @Override - public Node enter(final FunctionNode functionNode) { + public Node enterFunctionNode(final FunctionNode functionNode) { enterDefault(functionNode); - final boolean program = functionNode.isScript(); + final boolean program = functionNode.isProgram(); final String name; if (program) { name = "Program"; - } else if (functionNode.isStatement()) { + } else if (functionNode.isDeclared()) { name = "FunctionDeclaration"; } else { name = "FunctionExpression"; @@ -419,20 +419,11 @@ } // body consists of nested functions and statements - final List funcs = functionNode.getFunctions(); final List stats = functionNode.getStatements(); - final int size = stats.size() + funcs.size(); + final int size = stats.size(); int idx = 0; arrayStart("body"); - for (final Node func : funcs) { - func.accept(this); - if (idx != (size - 1)) { - comma(); - } - idx++; - } - for (final Node stat : stats) { if (! stat.isDebug()) { stat.accept(this); @@ -448,7 +439,7 @@ } @Override - public Node enter(final IdentNode identNode) { + public Node enterIdentNode(final IdentNode identNode) { enterDefault(identNode); final String name = identNode.getName(); @@ -464,7 +455,7 @@ } @Override - public Node enter(final IfNode ifNode) { + public Node enterIfNode(final IfNode ifNode) { enterDefault(ifNode); type("IfStatement"); @@ -490,7 +481,7 @@ } @Override - public Node enter(final IndexNode indexNode) { + public Node enterIndexNode(final IndexNode indexNode) { enterDefault(indexNode); type("MemberExpression"); @@ -510,7 +501,7 @@ } @Override - public Node enter(final LabelNode labelNode) { + public Node enterLabelNode(final LabelNode labelNode) { enterDefault(labelNode); type("LabeledStatement"); @@ -527,13 +518,13 @@ } @Override - public Node enter(final LineNumberNode lineNumberNode) { + public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { return null; } @SuppressWarnings("rawtypes") @Override - public Node enter(final LiteralNode literalNode) { + public Node enterLiteralNode(final LiteralNode literalNode) { enterDefault(literalNode); if (literalNode instanceof LiteralNode.ArrayLiteralNode) { @@ -569,7 +560,7 @@ } @Override - public Node enter(final ObjectNode objectNode) { + public Node enterObjectNode(final ObjectNode objectNode) { enterDefault(objectNode); type("ObjectExpression"); @@ -581,7 +572,7 @@ } @Override - public Node enter(final PropertyNode propertyNode) { + public Node enterPropertyNode(final PropertyNode propertyNode) { final Node key = propertyNode.getKey(); final Node value = propertyNode.getValue(); @@ -647,7 +638,7 @@ } @Override - public Node enter(final ReturnNode returnNode) { + public Node enterReturnNode(final ReturnNode returnNode) { enterDefault(returnNode); type("ReturnStatement"); @@ -665,7 +656,7 @@ } @Override - public Node enter(final RuntimeNode runtimeNode) { + public Node enterRuntimeNode(final RuntimeNode runtimeNode) { final RuntimeNode.Request req = runtimeNode.getRequest(); if (req == RuntimeNode.Request.DEBUGGER) { @@ -680,12 +671,12 @@ } @Override - public Node enter(final SplitNode splitNode) { + public Node enterSplitNode(final SplitNode splitNode) { return null; } @Override - public Node enter(final SwitchNode switchNode) { + public Node enterSwitchNode(final SwitchNode switchNode) { enterDefault(switchNode); type("SwitchStatement"); @@ -701,7 +692,7 @@ } @Override - public Node enter(final TernaryNode ternaryNode) { + public Node enterTernaryNode(final TernaryNode ternaryNode) { enterDefault(ternaryNode); type("ConditionalExpression"); @@ -722,7 +713,7 @@ } @Override - public Node enter(final ThrowNode throwNode) { + public Node enterThrowNode(final ThrowNode throwNode) { enterDefault(throwNode); type("ThrowStatement"); @@ -735,7 +726,7 @@ } @Override - public Node enter(final TryNode tryNode) { + public Node enterTryNode(final TryNode tryNode) { enterDefault(tryNode); type("TryStatement"); @@ -760,7 +751,7 @@ } @Override - public Node enter(final UnaryNode unaryNode) { + public Node enterUnaryNode(final UnaryNode unaryNode) { enterDefault(unaryNode); final TokenType tokenType = unaryNode.tokenType(); @@ -816,7 +807,7 @@ } @Override - public Node enter(final VarNode varNode) { + public Node enterVarNode(final VarNode varNode) { enterDefault(varNode); type("VariableDeclaration"); @@ -852,7 +843,7 @@ } @Override - public Node enter(final WhileNode whileNode) { + public Node enterWhileNode(final WhileNode whileNode) { enterDefault(whileNode); type("WhileStatement"); @@ -869,7 +860,7 @@ } @Override - public Node enter(final WithNode withNode) { + public Node enterWithNode(final WithNode withNode) { enterDefault(withNode); type("WithStatement"); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/debug/PrintVisitor.java --- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Tue Mar 26 12:08:00 2013 -0700 @@ -42,7 +42,6 @@ import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LineNumberNode; import jdk.nashorn.internal.ir.Node; -import jdk.nashorn.internal.ir.ReferenceNode; import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.SplitNode; @@ -138,13 +137,13 @@ * Visits. */ @Override - public Node enter(final AccessNode accessNode) { + public Node enterAccessNode(final AccessNode accessNode) { accessNode.toString(sb); return null; } @Override - public Node enter(final Block block) { + public Node enterBlock(final Block block) { sb.append(' '); sb.append('{'); @@ -152,21 +151,6 @@ final boolean isFunction = block instanceof FunctionNode; - if (isFunction) { - final FunctionNode function = (FunctionNode)block; - final List functions = function.getFunctions(); - - for (final FunctionNode f : functions) { - sb.append(EOLN); - indent(); - f.accept(this); - } - - if (!functions.isEmpty()) { - sb.append(EOLN); - } - } - final List statements = block.getStatements(); boolean lastLineNumber = false; @@ -224,25 +208,25 @@ } @Override - public Node enter(final BreakNode breakNode) { + public Node enterBreakNode(final BreakNode breakNode) { breakNode.toString(sb); return null; } @Override - public Node enter(final CallNode callNode) { + public Node enterCallNode(final CallNode callNode) { callNode.toString(sb); return null; } @Override - public Node enter(final ContinueNode continueNode) { + public Node enterContinueNode(final ContinueNode continueNode) { continueNode.toString(sb); return null; } @Override - public Node enter(final DoWhileNode doWhileNode) { + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { sb.append("do"); doWhileNode.getBody().accept(this); sb.append(' '); @@ -252,7 +236,7 @@ } @Override - public Node enter(final ExecuteNode executeNode) { + public Node enterExecuteNode(final ExecuteNode executeNode) { final Node expression = executeNode.getExpression(); if (expression instanceof UnaryNode) { @@ -265,7 +249,7 @@ } @Override - public Node enter(final ForNode forNode) { + public Node enterForNode(final ForNode forNode) { forNode.toString(sb); forNode.getBody().accept(this); @@ -273,15 +257,15 @@ } @Override - public Node enter(final FunctionNode functionNode) { + public Node enterFunctionNode(final FunctionNode functionNode) { functionNode.toString(sb); - enter((Block)functionNode); + enterBlock(functionNode); return null; } @Override - public Node enter(final IfNode ifNode) { + public Node enterIfNode(final IfNode ifNode) { ifNode.toString(sb); ifNode.getPass().accept(this); @@ -296,13 +280,13 @@ } @Override - public Node enter(final IndexNode indexNode) { + public Node enterIndexNode(final IndexNode indexNode) { indexNode.toString(sb); return null; } @Override - public Node enter(final LabelNode labeledNode) { + public Node enterLabelNode(final LabelNode labeledNode) { indent -= TABWIDTH; indent(); indent += TABWIDTH; @@ -313,7 +297,7 @@ } @Override - public Node enter(final LineNumberNode lineNumberNode) { + public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { if (printLineNumbers) { lineNumberNode.toString(sb); } @@ -323,25 +307,19 @@ @Override - public Node enter(final ReferenceNode referenceNode) { - referenceNode.toString(sb); - return null; - } - - @Override - public Node enter(final ReturnNode returnNode) { + public Node enterReturnNode(final ReturnNode returnNode) { returnNode.toString(sb); return null; } @Override - public Node enter(final RuntimeNode runtimeNode) { + public Node enterRuntimeNode(final RuntimeNode runtimeNode) { runtimeNode.toString(sb); return null; } @Override - public Node enter(final SplitNode splitNode) { + public Node enterSplitNode(final SplitNode splitNode) { splitNode.toString(sb); sb.append(EOLN); indent += TABWIDTH; @@ -350,7 +328,7 @@ } @Override - public Node leave(final SplitNode splitNode) { + public Node leaveSplitNode(final SplitNode splitNode) { sb.append(""); sb.append(EOLN); indent -= TABWIDTH; @@ -359,7 +337,7 @@ } @Override - public Node enter(final SwitchNode switchNode) { + public Node enterSwitchNode(final SwitchNode switchNode) { switchNode.toString(sb); sb.append(" {"); @@ -383,13 +361,13 @@ } @Override - public Node enter(final ThrowNode throwNode) { + public Node enterThrowNode(final ThrowNode throwNode) { throwNode.toString(sb); return null; } @Override - public Node enter(final TryNode tryNode) { + public Node enterTryNode(final TryNode tryNode) { tryNode.toString(sb); tryNode.getBody().accept(this); @@ -412,13 +390,19 @@ } @Override - public Node enter(final VarNode varNode) { - varNode.toString(sb); + public Node enterVarNode(final VarNode varNode) { + sb.append("var "); + varNode.getName().toString(sb); + final Node init = varNode.getInit(); + if(init != null) { + sb.append(" = "); + init.accept(this); + } return null; } @Override - public Node enter(final WhileNode whileNode) { + public Node enterWhileNode(final WhileNode whileNode) { whileNode.toString(sb); whileNode.getBody().accept(this); @@ -426,7 +410,7 @@ } @Override - public Node enter(final WithNode withNode) { + public Node enterWithNode(final WithNode withNode) { withNode.toString(sb); withNode.getBody().accept(this); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java --- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Tue Mar 26 12:08:00 2013 -0700 @@ -53,7 +53,7 @@ } @Override - public final Node enter(final UnaryNode unaryNode) { + public final Node enterUnaryNode(final UnaryNode unaryNode) { switch (unaryNode.tokenType()) { case ADD: return enterADD(unaryNode); @@ -81,12 +81,12 @@ case INCPOSTFIX: return enterDECINC(unaryNode); default: - return super.enter(unaryNode); + return super.enterUnaryNode(unaryNode); } } @Override - public final Node leave(final UnaryNode unaryNode) { + public final Node leaveUnaryNode(final UnaryNode unaryNode) { switch (unaryNode.tokenType()) { case ADD: return leaveADD(unaryNode); @@ -114,12 +114,12 @@ case INCPOSTFIX: return leaveDECINC(unaryNode); default: - return super.leave(unaryNode); + return super.leaveUnaryNode(unaryNode); } } @Override - public final Node enter(final BinaryNode binaryNode) { + public final Node enterBinaryNode(final BinaryNode binaryNode) { switch (binaryNode.tokenType()) { case ADD: return enterADD(binaryNode); @@ -198,12 +198,12 @@ case SUB: return enterSUB(binaryNode); default: - return super.enter(binaryNode); + return super.enterBinaryNode(binaryNode); } } @Override - public final Node leave(final BinaryNode binaryNode) { + public final Node leaveBinaryNode(final BinaryNode binaryNode) { switch (binaryNode.tokenType()) { case ADD: return leaveADD(binaryNode); @@ -282,7 +282,7 @@ case SUB: return leaveSUB(binaryNode); default: - return super.leave(binaryNode); + return super.leaveBinaryNode(binaryNode); } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java --- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Tue Mar 26 12:08:00 2013 -0700 @@ -49,7 +49,6 @@ import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ObjectNode; import jdk.nashorn.internal.ir.PropertyNode; -import jdk.nashorn.internal.ir.ReferenceNode; import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.SplitNode; @@ -153,7 +152,7 @@ * @param accessNode the node * @return processed node, null if traversal should end, null if traversal should end */ - public Node enter(final AccessNode accessNode) { + public Node enterAccessNode(final AccessNode accessNode) { return enterDefault(accessNode); } @@ -163,7 +162,7 @@ * @param accessNode the node * @return processed node, null if traversal should end */ - public Node leave(final AccessNode accessNode) { + public Node leaveAccessNode(final AccessNode accessNode) { return leaveDefault(accessNode); } @@ -173,7 +172,7 @@ * @param block the node * @return processed node, null if traversal should end */ - public Node enter(final Block block) { + public Node enterBlock(final Block block) { return enterDefault(block); } @@ -183,7 +182,7 @@ * @param block the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final Block block) { + public Node leaveBlock(final Block block) { return leaveDefault(block); } @@ -193,7 +192,7 @@ * @param binaryNode the node * @return processed node */ - public Node enter(final BinaryNode binaryNode) { + public Node enterBinaryNode(final BinaryNode binaryNode) { return enterDefault(binaryNode); } @@ -203,7 +202,7 @@ * @param binaryNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final BinaryNode binaryNode) { + public Node leaveBinaryNode(final BinaryNode binaryNode) { return leaveDefault(binaryNode); } @@ -213,7 +212,7 @@ * @param breakNode the node * @return processed node, null if traversal should end */ - public Node enter(final BreakNode breakNode) { + public Node enterBreakNode(final BreakNode breakNode) { return enterDefault(breakNode); } @@ -223,7 +222,7 @@ * @param breakNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final BreakNode breakNode) { + public Node leaveBreakNode(final BreakNode breakNode) { return leaveDefault(breakNode); } @@ -233,7 +232,7 @@ * @param callNode the node * @return processed node, null if traversal should end */ - public Node enter(final CallNode callNode) { + public Node enterCallNode(final CallNode callNode) { return enterDefault(callNode); } @@ -243,7 +242,7 @@ * @param callNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final CallNode callNode) { + public Node leaveCallNode(final CallNode callNode) { return leaveDefault(callNode); } @@ -253,7 +252,7 @@ * @param caseNode the node * @return processed node, null if traversal should end */ - public Node enter(final CaseNode caseNode) { + public Node enterCaseNode(final CaseNode caseNode) { return enterDefault(caseNode); } @@ -263,7 +262,7 @@ * @param caseNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final CaseNode caseNode) { + public Node leaveCaseNode(final CaseNode caseNode) { return leaveDefault(caseNode); } @@ -273,7 +272,7 @@ * @param catchNode the node * @return processed node, null if traversal should end */ - public Node enter(final CatchNode catchNode) { + public Node enterCatchNode(final CatchNode catchNode) { return enterDefault(catchNode); } @@ -283,7 +282,7 @@ * @param catchNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final CatchNode catchNode) { + public Node leaveCatchNode(final CatchNode catchNode) { return leaveDefault(catchNode); } @@ -293,7 +292,7 @@ * @param continueNode the node * @return processed node, null if traversal should end */ - public Node enter(final ContinueNode continueNode) { + public Node enterContinueNode(final ContinueNode continueNode) { return enterDefault(continueNode); } @@ -303,7 +302,7 @@ * @param continueNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final ContinueNode continueNode) { + public Node leaveContinueNode(final ContinueNode continueNode) { return leaveDefault(continueNode); } @@ -313,7 +312,7 @@ * @param doWhileNode the node * @return processed node */ - public Node enter(final DoWhileNode doWhileNode) { + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { return enterDefault(doWhileNode); } @@ -323,7 +322,7 @@ * @param doWhileNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final DoWhileNode doWhileNode) { + public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { return leaveDefault(doWhileNode); } @@ -333,7 +332,7 @@ * @param emptyNode the node * @return processed node */ - public Node enter(final EmptyNode emptyNode) { + public Node enterEmptyNode(final EmptyNode emptyNode) { return enterDefault(emptyNode); } @@ -343,7 +342,7 @@ * @param emptyNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final EmptyNode emptyNode) { + public Node leaveEmptyNode(final EmptyNode emptyNode) { return leaveDefault(emptyNode); } @@ -353,7 +352,7 @@ * @param executeNode the node * @return processed node, null if traversal should end */ - public Node enter(final ExecuteNode executeNode) { + public Node enterExecuteNode(final ExecuteNode executeNode) { return enterDefault(executeNode); } @@ -363,7 +362,7 @@ * @param executeNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final ExecuteNode executeNode) { + public Node leaveExecuteNode(final ExecuteNode executeNode) { return leaveDefault(executeNode); } @@ -373,7 +372,7 @@ * @param forNode the node * @return processed node, null if traversal should end */ - public Node enter(final ForNode forNode) { + public Node enterForNode(final ForNode forNode) { return enterDefault(forNode); } @@ -383,7 +382,7 @@ * @param forNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final ForNode forNode) { + public Node leaveForNode(final ForNode forNode) { return leaveDefault(forNode); } @@ -393,7 +392,7 @@ * @param functionNode the node * @return processed node */ - public Node enter(final FunctionNode functionNode) { + public Node enterFunctionNode(final FunctionNode functionNode) { return enterDefault(functionNode); } @@ -403,7 +402,7 @@ * @param functionNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final FunctionNode functionNode) { + public Node leaveFunctionNode(final FunctionNode functionNode) { return leaveDefault(functionNode); } @@ -413,7 +412,7 @@ * @param identNode the node * @return processed node, null if traversal should end */ - public Node enter(final IdentNode identNode) { + public Node enterIdentNode(final IdentNode identNode) { return enterDefault(identNode); } @@ -423,7 +422,7 @@ * @param identNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final IdentNode identNode) { + public Node leaveIdentNode(final IdentNode identNode) { return leaveDefault(identNode); } @@ -433,7 +432,7 @@ * @param ifNode the node * @return processed node, null if traversal should end */ - public Node enter(final IfNode ifNode) { + public Node enterIfNode(final IfNode ifNode) { return enterDefault(ifNode); } @@ -443,7 +442,7 @@ * @param ifNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final IfNode ifNode) { + public Node leaveIfNode(final IfNode ifNode) { return leaveDefault(ifNode); } @@ -453,7 +452,7 @@ * @param indexNode the node * @return processed node, null if traversal should end */ - public Node enter(final IndexNode indexNode) { + public Node enterIndexNode(final IndexNode indexNode) { return enterDefault(indexNode); } @@ -463,7 +462,7 @@ * @param indexNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final IndexNode indexNode) { + public Node leaveIndexNode(final IndexNode indexNode) { return leaveDefault(indexNode); } @@ -473,7 +472,7 @@ * @param labelNode the node * @return processed node, null if traversal should end */ - public Node enter(final LabelNode labelNode) { + public Node enterLabelNode(final LabelNode labelNode) { return enterDefault(labelNode); } @@ -483,7 +482,7 @@ * @param labelNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final LabelNode labelNode) { + public Node leaveLabelNode(final LabelNode labelNode) { return leaveDefault(labelNode); } @@ -493,7 +492,7 @@ * @param lineNumberNode the node * @return processed node, null if traversal should end */ - public Node enter(final LineNumberNode lineNumberNode) { + public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { return enterDefault(lineNumberNode); } @@ -503,7 +502,7 @@ * @param lineNumberNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final LineNumberNode lineNumberNode) { + public Node leaveLineNumberNode(final LineNumberNode lineNumberNode) { return leaveDefault(lineNumberNode); } @@ -513,8 +512,7 @@ * @param literalNode the node * @return processed node */ - @SuppressWarnings("rawtypes") - public Node enter(final LiteralNode literalNode) { + public Node enterLiteralNode(final LiteralNode literalNode) { return enterDefault(literalNode); } @@ -524,8 +522,7 @@ * @param literalNode the node * @return processed node, which will replace the original one, or the original node */ - @SuppressWarnings("rawtypes") - public Node leave(final LiteralNode literalNode) { + public Node leaveLiteralNode(final LiteralNode literalNode) { return leaveDefault(literalNode); } @@ -535,7 +532,7 @@ * @param objectNode the node * @return processed node */ - public Node enter(final ObjectNode objectNode) { + public Node enterObjectNode(final ObjectNode objectNode) { return enterDefault(objectNode); } @@ -545,7 +542,7 @@ * @param objectNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final ObjectNode objectNode) { + public Node leaveObjectNode(final ObjectNode objectNode) { return leaveDefault(objectNode); } @@ -555,7 +552,7 @@ * @param propertyNode the node * @return processed node, null if traversal should end */ - public Node enter(final PropertyNode propertyNode) { + public Node enterPropertyNode(final PropertyNode propertyNode) { return enterDefault(propertyNode); } @@ -565,37 +562,17 @@ * @param propertyNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final PropertyNode propertyNode) { + public Node leavePropertyNode(final PropertyNode propertyNode) { return leaveDefault(propertyNode); } /** - * Callback for entering a ReferenceNode - * - * @param referenceNode the node - * @return processed node, null if traversal should end - */ - public Node enter(final ReferenceNode referenceNode) { - return enterDefault(referenceNode); - } - - /** - * Callback for leaving a ReferenceNode - * - * @param referenceNode the node - * @return processed node, which will replace the original one, or the original node - */ - public Node leave(final ReferenceNode referenceNode) { - return leaveDefault(referenceNode); - } - - /** * Callback for entering a ReturnNode * * @param returnNode the node * @return processed node, null if traversal should end */ - public Node enter(final ReturnNode returnNode) { + public Node enterReturnNode(final ReturnNode returnNode) { return enterDefault(returnNode); } @@ -605,7 +582,7 @@ * @param returnNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final ReturnNode returnNode) { + public Node leaveReturnNode(final ReturnNode returnNode) { return leaveDefault(returnNode); } @@ -615,7 +592,7 @@ * @param runtimeNode the node * @return processed node, null if traversal should end */ - public Node enter(final RuntimeNode runtimeNode) { + public Node enterRuntimeNode(final RuntimeNode runtimeNode) { return enterDefault(runtimeNode); } @@ -625,7 +602,7 @@ * @param runtimeNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final RuntimeNode runtimeNode) { + public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { return leaveDefault(runtimeNode); } @@ -635,7 +612,7 @@ * @param splitNode the node * @return processed node, null if traversal should end */ - public Node enter(final SplitNode splitNode) { + public Node enterSplitNode(final SplitNode splitNode) { return enterDefault(splitNode); } @@ -645,7 +622,7 @@ * @param splitNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final SplitNode splitNode) { + public Node leaveSplitNode(final SplitNode splitNode) { return leaveDefault(splitNode); } @@ -655,7 +632,7 @@ * @param switchNode the node * @return processed node, null if traversal should end */ - public Node enter(final SwitchNode switchNode) { + public Node enterSwitchNode(final SwitchNode switchNode) { return enterDefault(switchNode); } @@ -665,7 +642,7 @@ * @param switchNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final SwitchNode switchNode) { + public Node leaveSwitchNode(final SwitchNode switchNode) { return leaveDefault(switchNode); } @@ -675,7 +652,7 @@ * @param ternaryNode the node * @return processed node, null if traversal should end */ - public Node enter(final TernaryNode ternaryNode) { + public Node enterTernaryNode(final TernaryNode ternaryNode) { return enterDefault(ternaryNode); } @@ -685,7 +662,7 @@ * @param ternaryNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final TernaryNode ternaryNode) { + public Node leaveTernaryNode(final TernaryNode ternaryNode) { return leaveDefault(ternaryNode); } @@ -695,7 +672,7 @@ * @param throwNode the node * @return processed node, null if traversal should end */ - public Node enter(final ThrowNode throwNode) { + public Node enterThrowNode(final ThrowNode throwNode) { return enterDefault(throwNode); } @@ -705,7 +682,7 @@ * @param throwNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final ThrowNode throwNode) { + public Node leaveThrowNode(final ThrowNode throwNode) { return leaveDefault(throwNode); } @@ -715,7 +692,7 @@ * @param tryNode the node * @return processed node, null if traversal should end */ - public Node enter(final TryNode tryNode) { + public Node enterTryNode(final TryNode tryNode) { return enterDefault(tryNode); } @@ -725,7 +702,7 @@ * @param tryNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final TryNode tryNode) { + public Node leaveTryNode(final TryNode tryNode) { return leaveDefault(tryNode); } @@ -735,7 +712,7 @@ * @param unaryNode the node * @return processed node, null if traversal should end */ - public Node enter(final UnaryNode unaryNode) { + public Node enterUnaryNode(final UnaryNode unaryNode) { return enterDefault(unaryNode); } @@ -745,7 +722,7 @@ * @param unaryNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final UnaryNode unaryNode) { + public Node leaveUnaryNode(final UnaryNode unaryNode) { return leaveDefault(unaryNode); } @@ -755,7 +732,7 @@ * @param varNode the node * @return processed node, null if traversal should end */ - public Node enter(final VarNode varNode) { + public Node enterVarNode(final VarNode varNode) { return enterDefault(varNode); } @@ -765,7 +742,7 @@ * @param varNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final VarNode varNode) { + public Node leaveVarNode(final VarNode varNode) { return leaveDefault(varNode); } @@ -775,7 +752,7 @@ * @param whileNode the node * @return processed node, null if traversal should end */ - public Node enter(final WhileNode whileNode) { + public Node enterWhileNode(final WhileNode whileNode) { return enterDefault(whileNode); } @@ -785,7 +762,7 @@ * @param whileNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final WhileNode whileNode) { + public Node leaveWhileNode(final WhileNode whileNode) { return leaveDefault(whileNode); } @@ -795,7 +772,7 @@ * @param withNode the node * @return processed node, null if traversal should end */ - public Node enter(final WithNode withNode) { + public Node enterWithNode(final WithNode withNode) { return enterDefault(withNode); } @@ -805,7 +782,7 @@ * @param withNode the node * @return processed node, which will replace the original one, or the original node */ - public Node leave(final WithNode withNode) { + public Node leaveWithNode(final WithNode withNode) { return leaveDefault(withNode); } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/objects/Global.java --- a/src/jdk/nashorn/internal/objects/Global.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/Global.java Tue Mar 26 12:08:00 2013 -0700 @@ -34,6 +34,9 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.ref.SoftReference; +import java.lang.reflect.Field; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -256,13 +259,29 @@ @Property(name = "Packages", attributes = Attribute.NOT_ENUMERABLE) public volatile Object packages; + /** Nashorn extension: Java access - global.com */ + @Property(attributes = Attribute.NOT_ENUMERABLE) + public volatile Object com; + + /** Nashorn extension: Java access - global.edu */ + @Property(attributes = Attribute.NOT_ENUMERABLE) + public volatile Object edu; + /** Nashorn extension: Java access - global.java */ @Property(attributes = Attribute.NOT_ENUMERABLE) public volatile Object java; + /** Nashorn extension: Java access - global.javafx */ + @Property(attributes = Attribute.NOT_ENUMERABLE) + public volatile Object javafx; + /** Nashorn extension: Java access - global.javax */ @Property(attributes = Attribute.NOT_ENUMERABLE) - public Object javax; + public volatile Object javax; + + /** Nashorn extension: Java access - global.org */ + @Property(attributes = Attribute.NOT_ENUMERABLE) + public volatile Object org; /** Nashorn extension: Java access - global.javaImporter */ @Property(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE) @@ -317,8 +336,12 @@ private ScriptFunction builtinTypeError; private ScriptFunction builtinURIError; private ScriptObject builtinPackages; + private ScriptObject builtinCom; + private ScriptObject builtinEdu; private ScriptObject builtinJava; + private ScriptObject builtinJavafx; private ScriptObject builtinJavax; + private ScriptObject builtinOrg; private ScriptObject builtinJavaImporter; private ScriptObject builtinJavaApi; private ScriptObject builtinArrayBuffer; @@ -1479,8 +1502,12 @@ private void initJavaAccess() { final ScriptObject objectProto = getObjectPrototype(); this.builtinPackages = new NativeJavaPackage("", objectProto); + this.builtinCom = new NativeJavaPackage("com", objectProto); + this.builtinEdu = new NativeJavaPackage("edu", objectProto); this.builtinJava = new NativeJavaPackage("java", objectProto); + this.builtinJavafx = new NativeJavaPackage("javafx", objectProto); this.builtinJavax = new NativeJavaPackage("javax", objectProto); + this.builtinOrg = new NativeJavaPackage("org", objectProto); this.builtinJavaImporter = initConstructor("JavaImporter"); this.builtinJavaApi = initConstructor("Java"); } @@ -1503,8 +1530,10 @@ addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value); // Nashorn extension: global.$OPTIONS (scripting-mode-only) - value = context.getEnv(); - addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, value); + final ScriptObject options = newEmptyInstance(); + final ScriptEnvironment scriptEnv = context.getEnv(); + copyOptions(options, scriptEnv); + addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options); // Nashorn extension: global.$ENV (scripting-mode-only) if (System.getSecurityManager() == null) { @@ -1523,6 +1552,22 @@ addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); } + private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + for (Field f : scriptEnv.getClass().getFields()) { + try { + options.set(f.getName(), f.get(scriptEnv), false); + } catch (final IllegalArgumentException | IllegalAccessException exp) { + throw new RuntimeException(exp); + } + } + return null; + } + }); + } + private void initTypedArray() { this.builtinArrayBuffer = initConstructor("ArrayBuffer"); this.builtinInt8Array = initConstructor("Int8Array"); @@ -1545,8 +1590,12 @@ this.function = this.builtinFunction; this.jsadapter = this.builtinJSAdapter; this.json = this.builtinJSON; + this.com = this.builtinCom; + this.edu = this.builtinEdu; this.java = this.builtinJava; + this.javafx = this.builtinJavafx; this.javax = this.builtinJavax; + this.org = this.builtinOrg; this.javaImporter = this.builtinJavaImporter; this.javaApi = this.builtinJavaApi; this.math = this.builtinMath; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/objects/NativeArray.java --- a/src/jdk/nashorn/internal/objects/NativeArray.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeArray.java Tue Mar 26 12:08:00 2013 -0700 @@ -605,7 +605,7 @@ final boolean strict = sobj.isStrictContext(); if (bulkable(sobj)) { - return ((NativeArray)sobj).getArray().pop(); + return sobj.getArray().pop(); } final long len = JSType.toUint32(sobj.getLength()); @@ -725,7 +725,7 @@ first = sobj.get(0); if (bulkable(sobj)) { - ((NativeArray) sobj).getArray().shiftLeft(1); + sobj.getArray().shiftLeft(1); } else { for (long k = 1; k < len; k++) { sobj.set(k - 1, sobj.get(k), strict); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/objects/NativeDebug.java --- a/src/jdk/nashorn/internal/objects/NativeDebug.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeDebug.java Tue Mar 26 12:08:00 2013 -0700 @@ -66,7 +66,7 @@ public static Object getContext(final Object self) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("getNashornContext")); + sm.checkPermission(new RuntimePermission("nashorn.getContext")); } return Global.getThisContext(); } @@ -162,21 +162,6 @@ } /** - * Nashorn extension: get invocation handle from {@link ScriptFunction} - * - * @param self self reference - * @param obj script function - * @return the invocation handle for the given ScriptFunction - */ - @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object methodHandle(final Object self, final Object obj) { - if (obj instanceof ScriptFunction) { - return ((ScriptFunction)obj).getInvokeHandle(); - } - return UNDEFINED; - } - - /** * Check object identity comparison regardless of type * * @param self self reference diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/objects/NativeError.java --- a/src/jdk/nashorn/internal/objects/NativeError.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeError.java Tue Mar 26 12:08:00 2013 -0700 @@ -317,7 +317,7 @@ return name; } // Step 10 : return name + ": " + msg - return (String)name + ": " + (String)msg; + return name + ": " + msg; } private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/objects/NativeJava.java --- a/src/jdk/nashorn/internal/objects/NativeJava.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeJava.java Tue Mar 26 12:08:00 2013 -0700 @@ -223,6 +223,23 @@ } /** + * Returns name of a java type {@link StaticClass}. + * @param self not used + * @param type the type whose name is returned + * @return name of the given type + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static Object typeName(final Object self, final Object type) { + if (type instanceof StaticClass) { + return ((StaticClass)type).getRepresentedClass().getName(); + } else if (type instanceof Class) { + return ((Class)type).getName(); + } else { + return UNDEFINED; + } + } + + /** * Given a JavaScript array and a Java type, returns a Java array with the same initial contents, and with the * specified component type. Example: *

diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/objects/NativeString.java
--- a/src/jdk/nashorn/internal/objects/NativeString.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeString.java	Tue Mar 26 12:08:00 2013 -0700
@@ -122,6 +122,19 @@
         return value.length();
     }
 
+    // This is to support length as method call as well.
+    @Override
+    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+        final String name = desc.getNameToken(2);
+
+        // if str.length(), then let the bean linker handle it
+        if ("length".equals(name) && "getMethod".equals(operator)) {
+            return null;
+        }
+
+        return super.findGetMethod(desc, request, operator);
+    }
+
     // This is to provide array-like access to string characters without creating a NativeString wrapper.
     @Override
     protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Tue Mar 26 12:08:00 2013 -0700
@@ -31,6 +31,7 @@
 import jdk.nashorn.internal.runtime.GlobalFunctions;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptFunctionData;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -86,8 +87,8 @@
      * @param builtin is this a built-in function
      * @param isConstructor can the function be used as a constructor (most can; some built-ins are restricted).
      */
-    ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) {
-        super(name, methodHandle, getMap(strict), scope, specs, strict, builtin, isConstructor);
+    ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
+        super(name, methodHandle, getMap(isStrict), scope, specs, isStrict, isBuiltin, isConstructor);
         init();
     }
 
@@ -95,14 +96,10 @@
      * Constructor called by (compiler) generated code for {@link ScriptObject}s.
      *
      * @param data static function data
-     * @param methodHandle handle for invocation
      * @param scope scope object
-     * @param allocator instance constructor for function
      */
-    public ScriptFunctionImpl(final MethodHandle methodHandle, final ScriptFunctionData data, final ScriptObject scope, final MethodHandle allocator) {
+    public ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope) {
         super(data, getMap(data.isStrict()), scope);
-        // Set method handles in script data
-        data.setMethodHandles(methodHandle, allocator);
         init();
     }
 
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java	Thu Mar 21 10:43:41 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-package jdk.nashorn.internal.objects;
-
-import static jdk.nashorn.internal.lookup.Lookup.MH;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import jdk.nashorn.internal.codegen.CompilationException;
-import jdk.nashorn.internal.codegen.Compiler;
-import jdk.nashorn.internal.codegen.FunctionSignature;
-import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.runtime.CodeInstaller;
-import jdk.nashorn.internal.runtime.Context;
-import jdk.nashorn.internal.runtime.ScriptEnvironment;
-import jdk.nashorn.internal.runtime.ScriptFunction;
-import jdk.nashorn.internal.runtime.ScriptFunctionData;
-import jdk.nashorn.internal.runtime.ScriptObject;
-
-/**
- * A trampoline is a promise to compile a {@link ScriptFunction} later. It just looks like
- * the call to the script function, but when invoked it will compile the script function
- * (in a new compile unit) and invoke it
- */
-public final class ScriptFunctionTrampolineImpl extends ScriptFunctionImpl {
-
-    private CodeInstaller installer;
-
-    /** Function node to lazily recompile when trampoline is hit */
-    private FunctionNode functionNode;
-
-    /**
-     * Constructor
-     *
-     * @param installer    opaque code installer from context
-     * @param functionNode function node to lazily compile when trampoline is hit
-     * @param data         {@link ScriptFunctionData} for function
-     * @param scope        scope
-     * @param allocator    allocator
-     */
-    public ScriptFunctionTrampolineImpl(final CodeInstaller installer, final FunctionNode functionNode, final ScriptFunctionData data, final ScriptObject scope, final MethodHandle allocator) {
-        super(null, data, scope, allocator);
-
-        this.installer    = installer;
-        this.functionNode = functionNode;
-
-        data.setMethodHandles(makeTrampoline(), allocator);
-    }
-
-    private final MethodHandle makeTrampoline() {
-        final MethodType mt =
-            new FunctionSignature(
-                true,
-                functionNode.needsCallee(),
-                Type.OBJECT,
-                functionNode.getParameters().size()).
-            getMethodType();
-
-        return
-            MH.bindTo(
-                MH.asCollector(
-                    findOwnMH(
-                        "trampoline",
-                        Object.class,
-                        Object[].class),
-                    Object[].class,
-                    mt.parameterCount()),
-                this);
-    }
-
-    private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) {
-        return MH.findVirtual(MethodHandles.lookup(), ScriptFunctionTrampolineImpl.class, name, MH.type(rtype, types));
-    }
-
-    @Override
-    protected ScriptFunction makeBoundFunction(final ScriptFunctionData data) {
-        //prevent trampoline recompilation cycle if a function is bound before use
-        compile();
-        return super.makeBoundFunction(data);
-    }
-
-    private MethodHandle compile() throws CompilationException {
-        final Compiler compiler = new Compiler(installer, functionNode);
-
-        compiler.compile();
-
-        final Class clazz = compiler.install();
-        /* compute function signature for lazy method. this can be done first after compilation, as only then do we know
-         * the final state about callees, scopes and specialized parameter types */
-        final FunctionSignature signature = new FunctionSignature(true, functionNode.needsCallee(), Type.OBJECT, functionNode.getParameters().size());
-        final MethodType        mt        = signature.getMethodType();
-
-        MethodHandle mh = MH.findStatic(MethodHandles.publicLookup(), clazz, functionNode.getName(), mt);
-        if (functionNode.needsCallee()) {
-            mh = MH.bindTo(mh, this);
-        }
-
-        // now the invoker method looks like the one our superclass is expecting
-        resetInvoker(mh);
-
-        return mh;
-    }
-
-    @SuppressWarnings("unused")
-    private Object trampoline(final Object... args) throws CompilationException {
-        Compiler.LOG.info(">>> TRAMPOLINE: Hitting trampoline for '" + functionNode.getName() + "'");
-        MethodHandle mh = compile();
-
-        Compiler.LOG.info("<<< COMPILED TO: " + mh);
-        // spread the array to invididual args of the correct type
-        mh = MH.asSpreader(mh, Object[].class, mh.type().parameterCount());
-
-        try {
-            //invoke the real method the trampoline points to. this only happens once
-            return mh.invoke(args);
-        } catch (final RuntimeException | Error e) {
-            throw e;
-        } catch (final Throwable t) {
-            throw new RuntimeException(t);
-        }
-    }
-}
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/parser/JSONParser.java
--- a/src/jdk/nashorn/internal/parser/JSONParser.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/parser/JSONParser.java	Tue Mar 26 12:08:00 2013 -0700
@@ -313,7 +313,7 @@
         }
 
         // Construct new object literal.
-        return new ObjectNode(source, objectToken, finish, null, elements);
+        return new ObjectNode(source, objectToken, finish, elements);
     }
 
     /**
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/parser/Parser.java
--- a/src/jdk/nashorn/internal/parser/Parser.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/parser/Parser.java	Tue Mar 26 12:08:00 2013 -0700
@@ -56,6 +56,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Stack;
@@ -75,17 +76,18 @@
 import jdk.nashorn.internal.ir.ExecuteNode;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.LabelNode;
+import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
 import jdk.nashorn.internal.ir.PropertyKey;
 import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.SwitchNode;
@@ -96,7 +98,6 @@
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.WhileNode;
 import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.JSErrorType;
@@ -116,19 +117,13 @@
     /** Is scripting mode. */
     private final boolean scripting;
 
-    /** Top level script being parsed. */
-    private FunctionNode script;
-
-    /** Current function being parsed. */
-    private FunctionNode function;
-
-    /** Current parsing block. */
-    private Block block;
+    private final LexicalContext lexicalContext = new LexicalContext();
+    private List functionDeclarations;
 
     /** Namespace for function names where not explicitly given */
     private final Namespace namespace;
 
-    private static DebugLogger LOG = new DebugLogger("parser");
+    private static final DebugLogger LOG = new DebugLogger("parser");
 
     /**
      * Constructor
@@ -279,7 +274,9 @@
      * @return New block.
      */
     private Block newBlock() {
-        return block = new Block(source, token, Token.descPosition(token), block, function);
+        final Block block = new Block(source, token, Token.descPosition(token));
+        lexicalContext.push(block);
+        return block;
     }
 
     /**
@@ -292,18 +289,23 @@
         // Build function name.
         final StringBuilder sb = new StringBuilder();
 
-        if (block != null) {
-            block.addParentName(sb);
+        final FunctionNode parentFunction = getFunction();
+        if(parentFunction != null && !parentFunction.isProgram()) {
+            sb.append(parentFunction.getName()).append('$');
         }
 
         sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag());
         final String name = namespace.uniqueName(sb.toString());
-        assert function != null || name.equals(RUN_SCRIPT.tag())  : "name = " + name;// must not rename runScript().
+        assert parentFunction != null || name.equals(RUN_SCRIPT.tag())  : "name = " + name;// must not rename runScript().
 
         // Start new block.
-        final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, block, ident, name);
-        block = function = functionBlock;
-        function.setStrictMode(isStrictMode);
+        final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, ident, name);
+        if(parentFunction == null) {
+            functionBlock.setProgram();
+        }
+        functionBlock.setStrictMode(isStrictMode);
+        functionBlock.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
+        lexicalContext.push(functionBlock);
 
         return functionBlock;
     }
@@ -311,9 +313,8 @@
     /**
      * Restore the current block.
      */
-    private void restoreBlock() {
-        block = block.getParent();
-        function = block.getFunction();
+    private void restoreBlock(Block block) {
+        lexicalContext.pop(block);
     }
 
     /**
@@ -323,22 +324,25 @@
     private Block getBlock(final boolean needsBraces) {
         // Set up new block. Captures LBRACE.
         final Block newBlock = newBlock();
-        pushControlNode(newBlock);
-
-        // Block opening brace.
-        if (needsBraces) {
-            expect(LBRACE);
+        try {
+            pushControlNode(newBlock);
+
+            // Block opening brace.
+            if (needsBraces) {
+                expect(LBRACE);
+            }
+
+            try {
+                // Accumulate block statements.
+                statementList();
+            } finally {
+                popControlNode();
+            }
+        } finally {
+            restoreBlock(newBlock);
         }
 
-        try {
-            // Accumulate block statements.
-            statementList();
-        } finally {
-            restoreBlock();
-            popControlNode();
-        }
-
-    final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
+        final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
 
         // Block closing brace.
         if (needsBraces) {
@@ -365,7 +369,7 @@
             // Accumulate statements.
             statement();
         } finally {
-            restoreBlock();
+            restoreBlock(newBlock);
         }
 
         return newBlock;
@@ -379,7 +383,10 @@
         final String name = ident.getName();
 
         if (EVAL.tag().equals(name)) {
-            function.setHasEval();
+            final Iterator it = lexicalContext.getFunctions();
+            if(it.hasNext()) {
+                it.next().setHasEval(it);
+            }
         }
     }
 
@@ -391,7 +398,7 @@
         final String name = ident.getName();
 
         if (ARGUMENTS.tag().equals(name)) {
-            function.setUsesArguments();
+            getFunction().setUsesArguments();
         }
     }
 
@@ -438,7 +445,7 @@
             }
 
             if (lhs instanceof IdentNode) {
-                if (! checkIdentLValue((IdentNode)lhs)) {
+                if (!checkIdentLValue((IdentNode)lhs)) {
                     return referenceError(lhs, rhs);
                 }
                 verifyStrictIdent((IdentNode)lhs, "assignment");
@@ -482,7 +489,7 @@
      * @return null or the found label node.
      */
     private LabelNode findLabel(final IdentNode ident) {
-        for (final LabelNode labelNode : function.getLabelStack()) {
+        for (final LabelNode labelNode : getFunction().getLabelStack()) {
             if (labelNode.getLabel().equals(ident)) {
                 return labelNode;
             }
@@ -496,14 +503,14 @@
      * @param labelNode Label to add.
      */
     private void pushLabel(final LabelNode labelNode) {
-        function.getLabelStack().push(labelNode);
+        getFunction().getLabelStack().push(labelNode);
     }
 
     /**
       * Remove a label from the label stack.
       */
     private void popLabel() {
-        function.getLabelStack().pop();
+        getFunction().getLabelStack().pop();
     }
 
     /**
@@ -513,6 +520,7 @@
     private void pushControlNode(final Node node) {
         final boolean isLoop = node instanceof WhileNode;
         final boolean isBreakable = node instanceof BreakableNode || node instanceof Block;
+        final FunctionNode function = getFunction();
         function.getControlStack().push(node);
 
         for (final LabelNode labelNode : function.getLabelStack()) {
@@ -531,7 +539,7 @@
      */
     private void popControlNode() {
         // Get control stack.
-        final Stack controlStack = function.getControlStack();
+        final Stack controlStack = getFunction().getControlStack();
 
         // Can be empty if missing brace.
         if (!controlStack.isEmpty()) {
@@ -541,7 +549,7 @@
 
     private void popControlNode(final Node node) {
         // Get control stack.
-        final Stack controlStack = function.getControlStack();
+        final Stack controlStack = getFunction().getControlStack();
 
         // Can be empty if missing brace.
         if (!controlStack.isEmpty() && controlStack.peek() == node) {
@@ -550,7 +558,7 @@
     }
 
     private boolean isInWithBlock() {
-        final Stack controlStack = function.getControlStack();
+        final Stack controlStack = getFunction().getControlStack();
         for (int i = controlStack.size() - 1; i >= 0; i--) {
             final Node node = controlStack.get(i);
 
@@ -563,7 +571,7 @@
     }
 
     private  T findControl(final Class ctype) {
-        final Stack controlStack = function.getControlStack();
+        final Stack controlStack = getFunction().getControlStack();
         for (int i = controlStack.size() - 1; i >= 0; i--) {
             final Node node = controlStack.get(i);
 
@@ -577,7 +585,7 @@
 
     private  List findControls(final Class ctype, final Node to) {
         final List nodes = new ArrayList<>();
-        final Stack controlStack = function.getControlStack();
+        final Stack controlStack = getFunction().getControlStack();
         for (int i = controlStack.size() - 1; i >= 0; i--) {
             final Node node = controlStack.get(i);
 
@@ -621,15 +629,16 @@
         // Make a fake token for the script.
         final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
         // Set up the script to append elements.
-        script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName));
-        // set kind to be SCRIPT
+
+        final FunctionNode script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName));
+
         script.setKind(FunctionNode.Kind.SCRIPT);
-        // Set the first token of the script.
         script.setFirstToken(functionToken);
-        // Gather source elements.
+        functionDeclarations = new ArrayList<>();
         sourceElements();
+        script.prependStatements(functionDeclarations);
+        functionDeclarations = null;
         expect(EOF);
-        // Set the last token of the script.
         script.setLastToken(token);
         script.setFinish(source.getLength() - 1);
 
@@ -707,7 +716,7 @@
                     // check for directive prologues
                     if (checkDirective) {
                         // skip any debug statement like line number to get actual first line
-                        final Node lastStatement = lastStatement(block.getStatements());
+                        final Node lastStatement = lastStatement(getBlock().getStatements());
 
                         // get directive prologue, if any
                         final String directive = getDirective(lastStatement);
@@ -727,6 +736,7 @@
                             // handle use strict directive
                             if ("use strict".equals(directive)) {
                                 isStrictMode = true;
+                                final FunctionNode function = getFunction();
                                 function.setStrictMode(true);
 
                                 // We don't need to check these, if lexical environment is already strict
@@ -799,11 +809,11 @@
             if (isStrictMode && !topLevel) {
                 error(AbstractParser.message("strict.no.func.here"), token);
             }
-            functionExpression(true);
+            functionExpression(true, topLevel);
             return;
         }
 
-        block.addStatement(lineNumberNode);
+        getBlock().addStatement(lineNumberNode);
 
         switch (type) {
         case LBRACE:
@@ -889,7 +899,7 @@
         // Force block execution.
         final ExecuteNode executeNode = new ExecuteNode(source, newBlock.getToken(), finish, newBlock);
 
-        block.addStatement(executeNode);
+        getBlock().addStatement(executeNode);
     }
 
     /**
@@ -984,13 +994,9 @@
 
             // Allocate var node.
             final VarNode var = new VarNode(source, varToken, finish, name, init);
-            if (isStatement) {
-                function.addDeclaration(var);
-            }
-
             vars.add(var);
             // Add to current block.
-            block.addStatement(var);
+            getBlock().addStatement(var);
 
             if (type != COMMARIGHT) {
                 break;
@@ -1003,7 +1009,7 @@
             boolean semicolon = type == SEMICOLON;
             endOfLine();
             if (semicolon) {
-                block.setFinish(finish);
+                getBlock().setFinish(finish);
             }
         }
 
@@ -1020,7 +1026,7 @@
      */
     private void emptyStatement() {
         if (env._empty_statements) {
-            block.addStatement(new EmptyNode(source, token,
+            getBlock().addStatement(new EmptyNode(source, token,
                     Token.descPosition(token) + Token.descLength(token)));
         }
 
@@ -1046,7 +1052,7 @@
         ExecuteNode executeNode = null;
         if (expression != null) {
             executeNode = new ExecuteNode(source, expressionToken, finish, expression);
-            block.addStatement(executeNode);
+            getBlock().addStatement(executeNode);
         } else {
             expect(null);
         }
@@ -1055,7 +1061,7 @@
 
         if (executeNode != null) {
             executeNode.setFinish(finish);
-            block.setFinish(finish);
+            getBlock().setFinish(finish);
         }
     }
 
@@ -1097,7 +1103,7 @@
         // Construct and add new if node.
         final IfNode ifNode = new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail);
 
-        block.addStatement(ifNode);
+        getBlock().addStatement(ifNode);
     }
 
     /**
@@ -1146,13 +1152,13 @@
             outer.setFinish(body.getFinish());
 
             // Add for to current block.
-            block.addStatement(forNode);
+            getBlock().addStatement(forNode);
         } finally {
-            restoreBlock();
+            restoreBlock(outer);
             popControlNode();
         }
 
-        block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+        getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
      }
 
     /**
@@ -1231,7 +1237,7 @@
                 }
 
                 if (init instanceof IdentNode) {
-                    if (! checkIdentLValue((IdentNode)init)) {
+                    if (!checkIdentLValue((IdentNode)init)) {
                         error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
                     }
                     verifyStrictIdent((IdentNode)init, "for-in iterator");
@@ -1286,7 +1292,7 @@
             whileNode.setFinish(statements.getFinish());
 
             // Add WHILE node.
-            block.addStatement(whileNode);
+            getBlock().addStatement(whileNode);
         } finally {
             popControlNode();
         }
@@ -1333,7 +1339,7 @@
             doWhileNode.setFinish(finish);
 
             // Add DO node.
-            block.addStatement(doWhileNode);
+            getBlock().addStatement(doWhileNode);
         } finally {
             popControlNode();
         }
@@ -1385,7 +1391,7 @@
         final ContinueNode continueNode = new ContinueNode(source, continueToken, finish, labelNode, targetNode, findControl(TryNode.class));
         continueNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
 
-        block.addStatement(continueNode);
+        getBlock().addStatement(continueNode);
     }
 
     /**
@@ -1433,7 +1439,7 @@
         final BreakNode breakNode = new BreakNode(source, breakToken, finish, labelNode, targetNode, findControl(TryNode.class));
         breakNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
 
-        block.addStatement(breakNode);
+        getBlock().addStatement(breakNode);
     }
 
     /**
@@ -1446,7 +1452,7 @@
      */
     private void returnStatement() {
         // check for return outside function
-        if (function.getKind() == FunctionNode.Kind.SCRIPT) {
+        if (getFunction().getKind() == FunctionNode.Kind.SCRIPT) {
             error(AbstractParser.message("invalid.return"));
         }
 
@@ -1473,7 +1479,7 @@
 
         // Construct and add RETURN node.
         final ReturnNode returnNode = new ReturnNode(source, returnToken, finish, expression, findControl(TryNode.class));
-        block.addStatement(returnNode);
+        getBlock().addStatement(returnNode);
     }
 
     /**
@@ -1508,7 +1514,7 @@
 
         // Construct and add YIELD node.
         final ReturnNode yieldNode = new ReturnNode(source, yieldToken, finish, expression, findControl(TryNode.class));
-        block.addStatement(yieldNode);
+        getBlock().addStatement(yieldNode);
     }
 
     /**
@@ -1532,7 +1538,10 @@
 
         // Get WITH expression.
         final WithNode withNode = new WithNode(source, withToken, finish, null, null);
-        function.setHasWith();
+        final Iterator it = lexicalContext.getFunctions();
+        if(it.hasNext()) {
+            it.next().setHasWith(it);
+        }
 
         try {
             pushControlNode(withNode);
@@ -1552,7 +1561,7 @@
             popControlNode(withNode);
         }
 
-        block.addStatement(withNode);
+        getBlock().addStatement(withNode);
     }
 
     /**
@@ -1652,7 +1661,7 @@
 
             switchNode.setFinish(finish);
 
-            block.addStatement(switchNode);
+            getBlock().addStatement(switchNode);
         } finally {
             popControlNode();
         }
@@ -1687,7 +1696,7 @@
             labelNode.setBody(statements);
             labelNode.setFinish(finish);
 
-            block.addStatement(labelNode);
+            getBlock().addStatement(labelNode);
         } finally {
             // Remove label.
             popLabel();
@@ -1730,7 +1739,7 @@
 
         // Construct and add THROW node.
         final ThrowNode throwNode = new ThrowNode(source, throwToken, finish, expression, findControl(TryNode.class));
-        block.addStatement(throwNode);
+        getBlock().addStatement(throwNode);
     }
 
     /**
@@ -1796,18 +1805,18 @@
 
                 expect(RPAREN);
 
+                final Block catchBlock = newBlock();
                 try {
-                    final Block catchBlock = newBlock();
 
                     // Get CATCH body.
                     final Block catchBody = getBlock(true);
 
                     // Create and add catch.
                     final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody);
-                    block.addStatement(catchNode);
+                    getBlock().addStatement(catchNode);
                     catchBlocks.add(catchBlock);
                 } finally {
-                    restoreBlock();
+                    restoreBlock(catchBlock);
                 }
 
                 // If unconditional catch then should to be the end.
@@ -1843,11 +1852,11 @@
             outer.addStatement(tryNode);
         } finally {
             popControlNode(tryNode);
-            restoreBlock();
+            restoreBlock(outer);
             popControlNode(outer);
         }
 
-        block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+        getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
     }
 
     /**
@@ -1867,7 +1876,7 @@
         endOfLine();
 
         final RuntimeNode runtimeNode = new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList());
-        block.addStatement(runtimeNode);
+        getBlock().addStatement(runtimeNode);
     }
 
     /**
@@ -2026,7 +2035,7 @@
                 break;
 
             default:
-                if (! elision) {
+                if (!elision) {
                     error(AbstractParser.message("expected.comma", type.getNameOrType()));
                 }
                 // Add expression element.
@@ -2067,15 +2076,11 @@
         next();
 
         // Object context.
-        Block objectContext = null;
         // Prepare to accumulate elements.
         final List elements = new ArrayList<>();
         final Map map = new HashMap<>();
 
-        try {
-            // Create a block for the object literal.
-            objectContext = newBlock();
-
+        // Create a block for the object literal.
             boolean commaSeen = true;
 loop:
             while (true) {
@@ -2090,97 +2095,90 @@
                     break;
 
                 default:
-                    if (! commaSeen) {
+                    if (!commaSeen) {
                         error(AbstractParser.message("expected.comma", type.getNameOrType()));
-                    }
-
-                    commaSeen = false;
-                    // Get and add the next property.
-                    final PropertyNode property = propertyAssignment();
-                    final Object key = property.getKeyName();
-                    final PropertyNode existingProperty = map.get(key);
-
-                    if (existingProperty != null) {
-                        // ECMA section 11.1.5 Object Initialiser
-                        // point # 4 on property assignment production
-                        final Node value  = property.getValue();
-                        final Node getter = property.getGetter();
-                        final Node setter = property.getSetter();
-
-                        final Node prevValue  = existingProperty.getValue();
-                        final Node prevGetter = existingProperty.getGetter();
-                        final Node prevSetter = existingProperty.getSetter();
-
-                        boolean redefinitionOk = true;
-                        // ECMA 11.1.5 strict mode restrictions
-                        if (isStrictMode) {
-                            if (value != null && prevValue != null) {
-                                redefinitionOk = false;
-                            }
-                        }
-
-                        final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
-                        final boolean isAccessor = getter != null || setter != null;
-
-                        // data property redefined as accessor property
-                        if (prevValue != null && isAccessor) {
-                            redefinitionOk = false;
-                        }
-
-                        // accessor property redefined as data
-                        if (isPrevAccessor && value != null) {
+                }
+
+                commaSeen = false;
+                // Get and add the next property.
+                final PropertyNode property = propertyAssignment();
+                final Object key = property.getKeyName();
+                final PropertyNode existingProperty = map.get(key);
+
+                if (existingProperty != null) {
+                    // ECMA section 11.1.5 Object Initialiser
+                    // point # 4 on property assignment production
+                    final Node value  = property.getValue();
+                    final Node getter = property.getGetter();
+                    final Node setter = property.getSetter();
+
+                    final Node prevValue  = existingProperty.getValue();
+                    final Node prevGetter = existingProperty.getGetter();
+                    final Node prevSetter = existingProperty.getSetter();
+
+                    boolean redefinitionOk = true;
+                    // ECMA 11.1.5 strict mode restrictions
+                    if (isStrictMode) {
+                        if (value != null && prevValue != null) {
                             redefinitionOk = false;
                         }
-
-                        if (isAccessor && isPrevAccessor) {
-                            if (getter != null && prevGetter != null ||
-                                setter != null && prevSetter != null) {
-                                redefinitionOk = false;
-                            }
-                        }
-
-                        if (! redefinitionOk) {
-                            error(AbstractParser.message("property.redefinition", key.toString()), property.getToken());
-                        }
-
-                        if (value != null) {
-                            final Node existingValue = existingProperty.getValue();
-
-                            if (existingValue == null) {
-                                existingProperty.setValue(value);
-                            } else {
-                                final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT);
-                                existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value));
-                            }
-
-                            existingProperty.setGetter(null);
-                            existingProperty.setSetter(null);
+                    }
+
+                    final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
+                    final boolean isAccessor = getter != null || setter != null;
+
+                    // data property redefined as accessor property
+                    if (prevValue != null && isAccessor) {
+                        redefinitionOk = false;
+                    }
+
+                    // accessor property redefined as data
+                    if (isPrevAccessor && value != null) {
+                        redefinitionOk = false;
+                    }
+
+                    if (isAccessor && isPrevAccessor) {
+                        if (getter != null && prevGetter != null ||
+                            setter != null && prevSetter != null) {
+                            redefinitionOk = false;
                         }
-
-                        if (getter != null) {
-                            existingProperty.setGetter(getter);
+                    }
+
+                    if (!redefinitionOk) {
+                        error(AbstractParser.message("property.redefinition", key.toString()), property.getToken());
+                    }
+
+                    if (value != null) {
+                        final Node existingValue = existingProperty.getValue();
+
+                        if (existingValue == null) {
+                            existingProperty.setValue(value);
+                        } else {
+                            final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT);
+                            existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value));
                         }
 
-                        if (setter != null) {
-                            existingProperty.setSetter(setter);
-                        }
-                    } else {
-                        map.put(key, property);
-                        elements.add(property);
+                        existingProperty.setGetter(null);
+                        existingProperty.setSetter(null);
                     }
 
-                    break;
+                    if (getter != null) {
+                        existingProperty.setGetter(getter);
+                    }
+
+                    if (setter != null) {
+                        existingProperty.setSetter(setter);
+                    }
+                } else {
+                    map.put(key, property);
+                    elements.add(property);
                 }
+
+                break;
             }
-        } finally {
-            restoreBlock();
         }
 
-        // Construct new object literal.
-        objectContext.setFinish(finish);
-        objectContext.setStart(Token.descPosition(objectToken));
-
-        return new ObjectNode(source, objectToken, finish, objectContext, elements);
+        return new ObjectNode(source, objectToken, finish, elements);
     }
 
     /**
@@ -2258,7 +2256,7 @@
                     parameters = new ArrayList<>();
                     functionNode = functionBody(getSetToken, getNameNode, parameters, FunctionNode.Kind.GETTER);
                     propertyNode = new PropertyNode(source, propertyToken, finish, getIdent, null);
-                    propertyNode.setGetter(new ReferenceNode(source, propertyToken, finish, functionNode));
+                    propertyNode.setGetter(functionNode);
                     return propertyNode;
 
                 case "set":
@@ -2273,7 +2271,7 @@
                     parameters.add(argIdent);
                     functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
                     propertyNode = new PropertyNode(source, propertyToken, finish, setIdent, null);
-                    propertyNode.setSetter(new ReferenceNode(source, propertyToken, finish, functionNode));
+                    propertyNode.setSetter(functionNode);
                     return propertyNode;
 
                 default:
@@ -2454,7 +2452,7 @@
 
         case FUNCTION:
             // Get function expression.
-            lhs = functionExpression(false);
+            lhs = functionExpression(false, false);
             break;
 
         default:
@@ -2559,7 +2557,7 @@
      *
      * @return Expression node.
      */
-    private Node functionExpression(final boolean isStatement) {
+    private Node functionExpression(final boolean isStatement, final boolean topLevel) {
         final LineNumberNode lineNumber = lineNumber();
 
         final long functionToken = token;
@@ -2594,10 +2592,12 @@
 
         final FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
 
-        if (isStatement && !isInWithBlock()) {
-            functionNode.setIsStatement();
+        if (isStatement) {
+            if(topLevel) {
+                functionNode.setIsDeclared();
+            }
             if(ARGUMENTS.tag().equals(name.getName())) {
-                functionNode.findParentFunction().setDefinesArguments();
+                getFunction().setDefinesArguments();
             }
         }
 
@@ -2605,8 +2605,6 @@
             functionNode.setIsAnonymous();
         }
 
-        final ReferenceNode referenceNode = new ReferenceNode(source, functionToken, finish, functionNode);
-
         final int arity = parameters.size();
 
         final boolean strict = functionNode.isStrictMode();
@@ -2642,17 +2640,18 @@
         }
 
         if (isStatement) {
-            final VarNode var = new VarNode(source, functionToken, finish, name, referenceNode);
-            if (isInWithBlock()) {
-                function.addDeclaration(var);
-                // Add to current block.
-                block.addStatement(var);
+            final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, true);
+            if(topLevel) {
+                functionDeclarations.add(lineNumber);
+                functionDeclarations.add(varNode);
             } else {
-                functionNode.setFunctionVarNode(var, lineNumber);
+                final Block block = getBlock();
+                block.addStatement(lineNumber);
+                block.addStatement(varNode);
             }
         }
 
-        return referenceNode;
+        return functionNode;
     }
 
     /**
@@ -2735,7 +2734,14 @@
                 expect(LBRACE);
 
                 // Gather the function elements.
-                sourceElements();
+                final List prevFunctionDecls = functionDeclarations;
+                functionDeclarations = new ArrayList<>();
+                try {
+                    sourceElements();
+                    functionNode.prependStatements(functionDeclarations);
+                } finally {
+                    functionDeclarations = prevFunctionDecls;
+                }
 
                 functionNode.setLastToken(token);
                 expect(RBRACE);
@@ -2743,12 +2749,9 @@
 
             }
         } finally {
-            restoreBlock();
+            restoreBlock(functionNode);
         }
 
-        // Add the body of the function to the current block.
-        block.addFunction(functionNode);
-
         return functionNode;
     }
 
@@ -2845,7 +2848,7 @@
             }
 
             if (lhs instanceof IdentNode) {
-                if (! checkIdentLValue((IdentNode)lhs)) {
+                if (!checkIdentLValue((IdentNode)lhs)) {
                     return referenceError(lhs, null);
                 }
                 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
@@ -2872,7 +2875,7 @@
                     return referenceError(lhs, null);
                 }
                 if (lhs instanceof IdentNode) {
-                    if (! checkIdentLValue((IdentNode)lhs)) {
+                    if (!checkIdentLValue((IdentNode)lhs)) {
                         next();
                         return referenceError(lhs, null);
                     }
@@ -3083,4 +3086,12 @@
     public String toString() {
         return "[JavaScript Parsing]";
     }
+
+    private Block getBlock() {
+        return lexicalContext.getCurrentBlock();
+    }
+
+    private FunctionNode getFunction() {
+        return lexicalContext.getCurrentFunction();
+    }
 }
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/AccessorProperty.java
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Tue Mar 26 12:08:00 2013 -0700
@@ -164,7 +164,6 @@
         super(key, flags, slot);
 
         /*
-         *
          * primitiveGetter and primitiveSetter are only used in dual fields mode. Setting them to null also
          * works in dual field mode, it only means that the property never has a primitive
          * representation.
@@ -348,11 +347,10 @@
 
     private MethodHandle debug(final MethodHandle mh, final Class forType, final Class type, final String tag) {
         if (DEBUG_FIELDS) {
-           final MethodHandle mhd = MethodHandleFactory.addDebugPrintout(
+           return MethodHandleFactory.addDebugPrintout(
                LOG,
                mh,
                tag + " '" + getKey() + "' (property="+ Debug.id(this) + ", forType=" + stripName(forType) + ", type=" + stripName(type) + ')');
-           return mhd;
         }
         return mh;
     }
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/CodeInstaller.java
--- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Tue Mar 26 12:08:00 2013 -0700
@@ -25,6 +25,8 @@
 
 package jdk.nashorn.internal.runtime;
 
+import jdk.nashorn.internal.codegen.ClassEmitter;
+
 /**
  * Interface for installing classes passed to the compiler.
  * As only the code generating package (i.e. Context) knows about
@@ -52,12 +54,12 @@
      */
     public Class install(final String className, final byte[] bytecode);
 
-    /*
+    /**
      * Verify generated bytecode before emission. This is called back from the
      * {@link ClassEmitter} or the {@link Compiler}. If the "--verify-code" parameter
      * hasn't been given, this is a nop
      *
-     * @param bytecode bytecode to verify
+     * @param code bytecode to verify
      */
     public void verify(final byte[] code);
 }
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/CompiledFunction.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Tue Mar 26 12:08:00 2013 -0700
@@ -0,0 +1,162 @@
+/*
+ * 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.  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.
+ */
+package jdk.nashorn.internal.runtime;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+
+import jdk.nashorn.internal.codegen.types.Type;
+
+/**
+ * An version of a JavaScript function, native or JavaScript.
+ * Supports lazily generating a constructor version of the invocation.
+ */
+final class CompiledFunction implements Comparable {
+
+    private final MethodHandle invoker;
+    private MethodHandle constructor;
+
+    CompiledFunction(final MethodHandle invoker) {
+        this(invoker, null);
+    }
+
+    CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
+        this.invoker = invoker;
+        this.constructor = constructor; //isConstructor
+    }
+
+    @Override
+    public String toString() {
+        return "";
+    }
+
+    MethodHandle getInvoker() {
+        return invoker;
+    }
+
+    MethodHandle getConstructor() {
+        return constructor;
+    }
+
+    void setConstructor(final MethodHandle constructor) {
+        this.constructor = constructor;
+    }
+
+    boolean hasConstructor() {
+        return constructor != null;
+    }
+
+    MethodType type() {
+        return invoker.type();
+    }
+
+    @Override
+    public int compareTo(final CompiledFunction o) {
+        return weight() - o.weight();
+    }
+
+    private int weight() {
+        return weight(type());
+    }
+
+    private static int weight(final MethodType type) {
+        if (isVarArgsType(type)) {
+            return Integer.MAX_VALUE; //if there is a varargs it should be the heavist and last fallback
+        }
+
+        int weight = Type.typeFor(type.returnType()).getWeight();
+        for (final Class paramType : type.parameterArray()) {
+            final int pweight = Type.typeFor(paramType).getWeight();
+            weight += pweight;
+        }
+        return weight;
+    }
+
+    private static boolean isVarArgsType(final MethodType type) {
+        assert type.parameterCount() >= 1 : type;
+        return type.parameterType(type.parameterCount() - 1) == Object[].class;
+    }
+
+    boolean moreGenericThan(final CompiledFunction o) {
+        return weight() > o.weight();
+    }
+
+    boolean moreGenericThan(final MethodType type) {
+        return weight() > weight(type);
+    }
+
+    /**
+     * Check whether a given method descriptor is compatible with this invocation.
+     * It is compatible if the types are narrower than the invocation type so that
+     * a semantically equivalent linkage can be performed.
+     *
+     * @param typesc
+     * @return
+     */
+    boolean typeCompatible(final MethodType type) {
+        final Class[] wantedParams   = type.parameterArray();
+        final Class[] existingParams = type().parameterArray();
+
+        //if we are not examining a varargs type, the number of parameters must be the same
+        if (wantedParams.length != existingParams.length && !isVarArgsType(type)) {
+            return false;
+        }
+
+        //we only go as far as the shortest array. the only chance to make this work if
+        //parameters lengths do not match is if our type ends with a varargs argument.
+        //then every trailing parameter in the given callsite can be folded into it, making
+        //us compatible (albeit slower than a direct specialization)
+        final int lastParamIndex = Math.min(wantedParams.length, existingParams.length);
+        for (int i = 0; i < lastParamIndex; i++) {
+            final Type w = Type.typeFor(wantedParams[i]);
+            final Type e = Type.typeFor(existingParams[i]);
+
+            //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution
+            //we also currently don't support boolean as a javascript function callsite type.
+            //it will always box.
+            if (w.isBoolean()) {
+                return false;
+            }
+
+            //This callsite type has a vararg here. it will swallow all remaining args.
+            //for consistency, check that it's the last argument
+            if (e.isArray()) {
+                return true;
+            }
+
+            //Our arguments must be at least as wide as the wanted one, if not wider
+            if (Type.widest(w, e) != e) {
+                //e.g. this invocation takes double and callsite says "object". reject. won't fit
+                //but if invocation takes a double and callsite says "int" or "long" or "double", that's fine
+                return false;
+            }
+        }
+
+        return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic.
+    }
+
+
+
+}
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/CompiledFunctions.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java	Tue Mar 26 12:08:00 2013 -0700
@@ -0,0 +1,73 @@
+/*
+ * 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.  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.
+ */
+package jdk.nashorn.internal.runtime;
+
+import java.lang.invoke.MethodType;
+import java.util.Iterator;
+import java.util.TreeSet;
+
+/**
+ * This is a list of code versions of a function.
+ * The list is sorted in ascending order of generic descriptors
+ */
+@SuppressWarnings("serial")
+final class CompiledFunctions extends TreeSet {
+
+    CompiledFunction best(final MethodType type) {
+        final Iterator iter = iterator();
+        while (iter.hasNext()) {
+            final CompiledFunction next = iter.next();
+            if (next.typeCompatible(type)) {
+                return next;
+            }
+        }
+        return mostGeneric();
+    }
+
+    boolean needsCallee() {
+        for (final CompiledFunction inv : this) {
+            assert ScriptFunctionData.needsCallee(inv.getInvoker()) == ScriptFunctionData.needsCallee(mostGeneric().getInvoker());
+        }
+        return ScriptFunctionData.needsCallee(mostGeneric().getInvoker());
+    }
+
+    CompiledFunction mostGeneric() {
+        return last();
+    }
+
+    /**
+     * Is the given type even more specific than this entire list? That means
+     * we have an opportunity for more specific versions of the method
+     * through lazy code generation
+     *
+     * @param type type to check against
+     * @return true if the given type is more specific than all invocations available
+     */
+    boolean isLessSpecificThan(final MethodType type) {
+        return best(type).moreGenericThan(type);
+    }
+
+
+}
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/Context.java
--- a/src/jdk/nashorn/internal/runtime/Context.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/runtime/Context.java	Tue Mar 26 12:08:00 2013 -0700
@@ -27,9 +27,9 @@
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
+import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
 
 import java.io.File;
 import java.io.IOException;
@@ -39,10 +39,13 @@
 import java.lang.reflect.Constructor;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.CodeSigner;
 import java.security.CodeSource;
+import java.security.Permissions;
 import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
 import jdk.nashorn.internal.codegen.Compiler;
@@ -77,7 +80,7 @@
 
         /**
          * Return the context for this installer
-         * @return context
+         * @return ScriptEnvironment
          */
         @Override
         public ScriptEnvironment getOwner() {
@@ -123,7 +126,7 @@
             if (callerLoader != myLoader &&
                 !(callerLoader instanceof StructureLoader) &&
                 !(JavaAdapterFactory.isAdapterClass(caller))) {
-                sm.checkPermission(new RuntimePermission("getNashornGlobal"));
+                sm.checkPermission(new RuntimePermission("nashorn.getGlobal"));
             }
         }
 
@@ -137,7 +140,7 @@
     public static void setGlobal(final ScriptObject global) {
         final SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            sm.checkPermission(new RuntimePermission("setNashornGlobal"));
+            sm.checkPermission(new RuntimePermission("nashorn.setGlobal"));
         }
 
         if (global != null && !(global instanceof GlobalObject)) {
@@ -154,7 +157,7 @@
     public static Context getContext() {
         final SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            sm.checkPermission(new RuntimePermission("getNashornContext"));
+            sm.checkPermission(new RuntimePermission("nashorn.getContext"));
         }
         return getContextTrusted();
     }
@@ -267,7 +270,7 @@
     public Context(final Options options, final ErrorManager errors, final PrintWriter out, final PrintWriter err, final ClassLoader appLoader) {
         final SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            sm.checkPermission(new RuntimePermission("createNashornContext"));
+            sm.checkPermission(new RuntimePermission("nashorn.createContext"));
         }
 
         this.env       = new ScriptEnvironment(options, out, err);
@@ -533,7 +536,13 @@
         if (index != -1) {
             final SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
-                sm.checkPackageAccess(fullName.substring(0, index));
+                AccessController.doPrivileged(new PrivilegedAction() {
+                    @Override
+                    public Void run() {
+                        sm.checkPackageAccess(fullName.substring(0, index));
+                        return null;
+                    }
+                }, createNoPermissionsContext());
             }
         }
 
@@ -599,7 +608,7 @@
     public ScriptObject newGlobal() {
         final SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            sm.checkPermission(new RuntimePermission("createNashornGlobal"));
+            sm.checkPermission(new RuntimePermission("nashorn.newGlobal"));
         }
 
         return newGlobalTrusted();
@@ -676,6 +685,10 @@
         return (context != null) ? context : Context.getContextTrusted();
     }
 
+    private static AccessControlContext createNoPermissionsContext() {
+        return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) });
+    }
+
     private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
         ScriptFunction script = null;
 
@@ -731,6 +744,7 @@
             global = (GlobalObject)Context.getGlobalTrusted();
             script = global.findCachedClass(source);
             if (script != null) {
+                Compiler.LOG.fine("Code cache hit for " + source + " avoiding recompile.");
                 return script;
             }
         }
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/ECMAException.java
--- a/src/jdk/nashorn/internal/runtime/ECMAException.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/runtime/ECMAException.java	Tue Mar 26 12:08:00 2013 -0700
@@ -237,7 +237,7 @@
             return (String)name;
         }
 
-        return (String)name + ": " + (String)msg;
+        return name + ": " + msg;
     }
 
     private static Throwable asThrowable(final Object obj) {
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Tue Mar 26 12:08:00 2013 -0700
@@ -0,0 +1,100 @@
+/*
+ * 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.  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.
+ */
+
+package jdk.nashorn.internal.runtime;
+
+import static jdk.nashorn.internal.lookup.Lookup.MH;
+
+import java.lang.invoke.MethodHandle;
+
+/**
+ * This is a subclass that represents a script function that may not be regenerated.
+ * This is used for example for bound functions and builtins.
+ */
+public final class FinalScriptFunctionData extends ScriptFunctionData {
+
+    /**
+     * Constructor - used for bind
+     *
+     * @param name          name
+     * @param arity         arity
+     * @param list          precompiled code
+     * @param isStrict      strict
+     * @param isBuiltin     builtin
+     * @param isConstructor constructor
+     */
+    FinalScriptFunctionData(final String name, int arity, CompiledFunctions functions, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
+        super(name, arity, isStrict, isBuiltin, isConstructor);
+        code.addAll(functions);
+    }
+
+    /**
+     * Constructor - used from ScriptFunction. This assumes that we have code alraedy for the
+     * method (typically a native method) and possibly specializations.
+     *
+     * @param name           name
+     * @param mh             method handle for generic version of method
+     * @param specs          specializations
+     * @param isStrict       strict
+     * @param isBuiltin      builtin
+     * @param isConstructor  constructor
+     */
+    FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
+        super(name, arity(mh), isStrict, isBuiltin, isConstructor);
+
+        addInvoker(mh);
+        if (specs != null) {
+            for (final MethodHandle spec : specs) {
+                addInvoker(spec);
+            }
+        }
+    }
+
+    private void addInvoker(final MethodHandle mh) {
+        boolean needsCallee = needsCallee(mh);
+        if (isConstructor(mh)) {
+            //only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor
+            //is too conservative a check. However, isConstructor(mh) always implies isConstructor param
+            assert isConstructor();
+            code.add(new CompiledFunction(MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor
+        } else {
+            code.add(new CompiledFunction(mh));
+        }
+    }
+
+    private static int arity(final MethodHandle mh) {
+        if (isVarArg(mh)) {
+            return -1;
+        }
+
+        //drop self, callee and boolean constructor flag to get real arity
+        return mh.type().parameterCount() - 1 - (needsCallee(mh) ? 1 : 0) - (isConstructor(mh) ? 1 : 0);
+    }
+
+    private static boolean isConstructor(final MethodHandle mh) {
+        return mh.type().parameterCount() >= 1 && mh.type().parameterType(0) == boolean.class;
+    }
+
+}
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/NashornLoader.java
--- a/src/jdk/nashorn/internal/runtime/NashornLoader.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/runtime/NashornLoader.java	Tue Mar 26 12:08:00 2013 -0700
@@ -30,6 +30,10 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
 import java.security.SecureClassLoader;
 import jdk.nashorn.tools.Shell;
 
@@ -40,6 +44,28 @@
  *
  */
 abstract class NashornLoader extends SecureClassLoader {
+    private static final String OBJECTS_PKG = "jdk.nashorn.internal.objects";
+    private static final String RUNTIME_PKG = "jdk.nashorn.internal.runtime";
+    private static final String RUNTIME_LINKER_PKG = "jdk.nashorn.internal.runtime.linker";
+    private static final String SCRIPTS_PKG = "jdk.nashorn.internal.scripts";
+
+    private static final Permission[] SCRIPT_PERMISSIONS;
+    static {
+        SCRIPT_PERMISSIONS = new Permission[4];
+
+        /*
+         * Generated classes get access to runtime, runtime.linker, objects, scripts packages.
+         * Note that the actual scripts can not access these because Java.type, Packages
+         * prevent these restricted packages. And Java reflection and JSR292 access is prevented
+         * for scripts. In other words, nashorn generated portions of script classes can access
+         * clases in these implementation packages.
+         */
+        SCRIPT_PERMISSIONS[0] = new RuntimePermission("accessClassInPackage." + RUNTIME_PKG);
+        SCRIPT_PERMISSIONS[1] = new RuntimePermission("accessClassInPackage." + RUNTIME_LINKER_PKG);
+        SCRIPT_PERMISSIONS[2] = new RuntimePermission("accessClassInPackage." + OBJECTS_PKG);
+        SCRIPT_PERMISSIONS[3] = new RuntimePermission("accessClassInPackage." + SCRIPTS_PKG);
+    }
+
     private final Context context;
 
     final Context getContext() {
@@ -68,11 +94,30 @@
         if (i != -1) {
             final SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
-                sm.checkPackageAccess(name.substring(0, i));
+                final String pkgName = name.substring(0, i);
+                switch (pkgName) {
+                    case RUNTIME_PKG:
+                    case RUNTIME_LINKER_PKG:
+                    case OBJECTS_PKG:
+                    case SCRIPTS_PKG:
+                        // allow it.
+                        break;
+                    default:
+                        sm.checkPackageAccess(pkgName);
+                }
             }
         }
     }
 
+    @Override
+    protected PermissionCollection getPermissions(CodeSource codesource) {
+        final Permissions permCollection = new Permissions();
+        for (final Permission perm : SCRIPT_PERMISSIONS) {
+            permCollection.add(perm);
+        }
+        return permCollection;
+    }
+
     /**
      * Create a secure URL class loader for the given classpath
      * @param classPath classpath for the loader to search from
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Tue Mar 26 12:08:00 2013 -0700
@@ -0,0 +1,185 @@
+/*
+ * 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.  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.
+ */
+
+package jdk.nashorn.internal.runtime;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import jdk.nashorn.internal.codegen.Compiler;
+import jdk.nashorn.internal.codegen.CompilerConstants;
+import jdk.nashorn.internal.codegen.FunctionSignature;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.parser.Token;
+import jdk.nashorn.internal.parser.TokenType;
+
+import static jdk.nashorn.internal.lookup.Lookup.MH;
+
+/**
+ * This is a subclass that represents a script function that may be regenerated,
+ * for example with specialization based on call site types, or lazily generated.
+ * The common denominator is that it can get new invokers during its lifespan,
+ * unlike {@link FinalScriptFunctionData}
+ */
+public final class RecompilableScriptFunctionData extends ScriptFunctionData {
+
+    private final FunctionNode functionNode;
+    private final PropertyMap  allocatorMap;
+    private final CodeInstaller installer;
+    private final String allocatorClassName;
+
+    /** lazily generated allocator */
+    private MethodHandle allocator;
+
+    private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
+    /**
+     * Constructor - public as scripts use it
+     *
+     * @param functionNode       functionNode that represents this function code
+     * @param installer          installer for code regeneration versions of this function
+     * @param allocatorClassName name of our allocator class, will be looked up dynamically if used as a constructor
+     * @param allocatorMap       allocator map to seed instances with, when constructing
+     */
+    public RecompilableScriptFunctionData(final FunctionNode functionNode, final CodeInstaller installer, final String allocatorClassName, final PropertyMap allocatorMap) {
+        super(functionNode.isAnonymous() ?
+                "" :
+                functionNode.getIdent().getName(),
+              functionNode.getParameters().size(),
+              functionNode.isStrictMode(),
+              false,
+              true);
+
+        this.functionNode       = functionNode;
+        this.installer          = installer;
+        this.allocatorClassName = allocatorClassName;
+        this.allocatorMap       = allocatorMap;
+    }
+
+    @Override
+    String toSource() {
+        final Source source = functionNode.getSource();
+        final long   token  = tokenFor(functionNode);
+
+        if (source != null && token != 0) {
+            return source.getString(Token.descPosition(token), Token.descLength(token));
+        }
+
+        return "function " + (name == null ? "" : name) + "() { [native code] }";
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        final Source source = functionNode.getSource();
+        final long   token  = tokenFor(functionNode);
+
+        if (source != null) {
+            sb.append(source.getName())
+                .append(':')
+                .append(source.getLine(Token.descPosition(token)))
+                .append(' ');
+        }
+
+        return sb.toString() + super.toString();
+    }
+
+    private static long tokenFor(final FunctionNode fn) {
+        final int  position   = Token.descPosition(fn.getFirstToken());
+        final int  length     = Token.descPosition(fn.getLastToken()) - position + Token.descLength(fn.getLastToken());
+
+        return Token.toDesc(TokenType.FUNCTION, position, length);
+    }
+
+    @Override
+    ScriptObject allocate() {
+        try {
+            ensureHasAllocator(); //if allocatorClass name is set to null (e.g. for bound functions) we don't even try
+            return allocator == null ? null : (ScriptObject)allocator.invokeExact(allocatorMap);
+        } catch (final RuntimeException | Error e) {
+            throw e;
+        } catch (final Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    private void ensureHasAllocator() throws ClassNotFoundException {
+        if (allocator == null && allocatorClassName != null) {
+            this.allocator = MH.findStatic(LOOKUP, Context.forStructureClass(allocatorClassName), CompilerConstants.ALLOCATE.tag(), MH.type(ScriptObject.class, PropertyMap.class));
+        }
+    }
+
+    @Override
+    protected void ensureCodeGenerated() {
+         if (!code.isEmpty()) {
+             return; // nothing to do, we have code, at least some.
+         }
+
+         // check if function node is lazy, need to compile it.
+         // note that currently function cloning is not working completely, which
+         // means that the compiler will mutate the function node it has been given
+         // once it has been compiled, it cannot be recompiled. This means that
+         // lazy compilation works (not compiled yet) but e.g. specializations won't
+         // until the copy-on-write changes for IR are in, making cloning meaningless.
+         // therefore, currently method specialization is disabled. TODO
+
+         if (functionNode.isLazy()) {
+             Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '" + functionNode.getName() + "'");
+             new Compiler(installer, functionNode).compile().install();
+
+             // we don't need to update any flags - varArgs and needsCallee are instrincic
+             // in the function world we need to get a destination node from the compile instead
+             // and replace it with our function node. TODO
+         }
+
+         // we can't get here unless we have bytecode, either from eager compilation or from
+         // running a lazy compile on the lines above
+
+         assert functionNode.hasState(CompilationState.INSTALLED);
+
+         // code exists - look it up and add it into the automatically sorted invoker list
+         code.add(
+            new CompiledFunction(
+                MH.findStatic(
+                    LOOKUP,
+                    functionNode.getCompileUnit().getCode(),
+                    functionNode.getName(),
+                    new FunctionSignature(functionNode).
+                        getMethodType())));
+    }
+
+    @Override
+    MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
+        final MethodHandle mh = super.getBestInvoker(callSiteType, args);
+        if (code.isLessSpecificThan(callSiteType)) {
+            // opportunity for code specialization - we can regenerate a better version of this method
+        }
+        return mh;
+    }
+
+}
+
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Tue Mar 26 12:08:00 2013 -0700
@@ -82,6 +82,9 @@
     /** Show full Nashorn version */
     public final boolean _fullversion;
 
+    /** Should lazy compilation take place */
+    public final boolean _lazy_compilation;
+
     /** Create a new class loaded for each compilation */
     public final boolean _loader_per_compile;
 
@@ -155,6 +158,7 @@
         _early_lvalue_error   = options.getBoolean("early.lvalue.error");
         _empty_statements     = options.getBoolean("empty.statements");
         _fullversion          = options.getBoolean("fullversion");
+        _lazy_compilation     = options.getBoolean("lazy.compilation");
         _loader_per_compile   = options.getBoolean("loader.per.compile");
         _no_syntax_extensions = options.getBoolean("no.syntax.extensions");
         _package              = options.getString("package");
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/ScriptFunction.java
--- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Tue Mar 26 12:08:00 2013 -0700
@@ -33,11 +33,11 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
-import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import jdk.nashorn.internal.runtime.linker.NashornGuards;
@@ -48,16 +48,16 @@
 public abstract class ScriptFunction extends ScriptObject {
 
     /** Method handle for prototype getter for this ScriptFunction */
-    public static final MethodHandle G$PROTOTYPE  = findOwnMH("G$prototype",  Object.class, Object.class);
+    public static final MethodHandle G$PROTOTYPE = findOwnMH("G$prototype", Object.class, Object.class);
 
     /** Method handle for prototype setter for this ScriptFunction */
-    public static final MethodHandle S$PROTOTYPE  = findOwnMH("S$prototype",  void.class, Object.class, Object.class);
+    public static final MethodHandle S$PROTOTYPE = findOwnMH("S$prototype", void.class, Object.class, Object.class);
 
     /** Method handle for length getter for this ScriptFunction */
-    public static final MethodHandle G$LENGTH     = findOwnMH("G$length",     int.class, Object.class);
+    public static final MethodHandle G$LENGTH = findOwnMH("G$length", int.class, Object.class);
 
     /** Method handle for name getter for this ScriptFunction */
-    public static final MethodHandle G$NAME       = findOwnMH("G$name",       Object.class, Object.class);
+    public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class);
 
     /** Method handle for allocate function for this ScriptFunction */
     static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class);
@@ -67,7 +67,9 @@
     /** method handle to scope getter for this ScriptFunction */
     public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
 
-    private final ScriptFunctionData data;
+    private static final MethodHandle IS_FUNCTION_MH  = findOwnMH("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class);
+
+    private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
 
     /** Reference to constructor prototype. */
     protected Object prototype;
@@ -75,6 +77,8 @@
     /** The parent scope. */
     private final ScriptObject scope;
 
+    private final ScriptFunctionData data;
+
     /**
      * Constructor
      *
@@ -97,7 +101,7 @@
             final boolean builtin,
             final boolean isConstructor) {
 
-        this (new ScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope);
+        this(new FinalScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope);
     }
 
     /**
@@ -118,8 +122,8 @@
             constructorCount++;
         }
 
-        this.data = data;
-        this.scope  = scope;
+        this.data  = data;
+        this.scope = scope;
     }
 
     @Override
@@ -295,20 +299,20 @@
     /**
      * Return the most appropriate invoke handle if there are specializations
      * @param type most specific method type to look for invocation with
+     * @param callsite args for trampoline invocation
      * @return invoke method handle
      */
-    private final MethodHandle getBestInvoker(final MethodType type) {
-        return data.getBestInvoker(type);
+    private MethodHandle getBestInvoker(final MethodType type, final Object[] args) {
+        return data.getBestInvoker(type, args);
     }
 
     /**
-     * Get the invoke handle - the most generic (and if no specializations are in place, only) invocation
-     * method handle for this ScriptFunction
-     * @see SpecializedFunction
-     * @return invokeHandle
+     * Return the most appropriate invoke handle if there are specializations
+     * @param type most specific method type to look for invocation with
+     * @return invoke method handle
      */
-    public final MethodHandle getInvokeHandle() {
-        return data.getInvoker();
+    public MethodHandle getBestInvoker(final MethodType type) {
+        return getBestInvoker(type, null);
     }
 
     /**
@@ -319,7 +323,7 @@
      * @return bound invoke handle
      */
     public final MethodHandle getBoundInvokeHandle(final ScriptObject self) {
-        return MH.bindTo(bindToCalleeIfNeeded(getInvokeHandle()), self);
+        return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker()), self);
     }
 
     /**
@@ -329,7 +333,8 @@
      * @return the potentially bound method handle
      */
     private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) {
-        return data.needsCallee() ? MH.bindTo(methodHandle, this) : methodHandle;
+        return ScriptFunctionData.needsCallee(methodHandle) ? MH.bindTo(methodHandle, this) : methodHandle;
+
     }
 
     /**
@@ -340,15 +345,6 @@
         return data.getName();
     }
 
-    /**
-     * Does this script function need to be compiled. This determined by
-     * null checking invokeHandle
-     *
-     * @return true if this needs compilation
-     */
-    public final boolean needsCompilation() {
-        return data.getInvoker() == null;
-    }
 
     /**
      * Get the scope for this function
@@ -359,15 +355,6 @@
     }
 
     /**
-     * Reset the invoker handle. This is used by trampolines for
-     * lazy code generation
-     * @param invoker new invoker
-     */
-    protected void resetInvoker(final MethodHandle invoker) {
-        data.resetInvoker(invoker);
-    }
-
-    /**
      * Prototype getter for this ScriptFunction - follows the naming convention
      * used by Nasgen and the code generator
      *
@@ -464,7 +451,7 @@
     @Override
     protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
         final MethodType type = desc.getMethodType();
-        return new GuardedInvocation(pairArguments(data.getBestConstructor(type), type), null, NashornGuards.getFunctionGuard(this));
+        return new GuardedInvocation(pairArguments(data.getBestConstructor(type.changeParameterType(0, ScriptFunction.class), null), type), null, getFunctionGuard(this));
     }
 
     @SuppressWarnings("unused")
@@ -472,7 +459,7 @@
         if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
             return obj;
         }
-        return ((GlobalObject) Context.getGlobalTrusted()).wrapAsObject(obj);
+        return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(obj);
     }
 
     /**
@@ -506,8 +493,7 @@
         MethodHandle guard = null;
 
         if (data.needsCallee()) {
-            final MethodHandle callHandle = getBestInvoker(type);
-
+            final MethodHandle callHandle = getBestInvoker(type, request.getArguments());
             if (NashornCallSiteDescriptor.isScope(desc)) {
                 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
                 // (callee, this, args...) => (callee, args...)
@@ -525,13 +511,12 @@
                     if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) {
                         boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
                     } else {
-                        guard = NashornGuards.getNonStrictFunctionGuard(this);
+                        guard = getNonStrictFunctionGuard(this);
                     }
                 }
             }
         } else {
-            final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1));
-
+            final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1), request.getArguments());
             if (NashornCallSiteDescriptor.isScope(desc)) {
                 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
                 // (this, args...) => (args...)
@@ -545,7 +530,8 @@
         }
 
         boundHandle = pairArguments(boundHandle, type);
-        return new GuardedInvocation(boundHandle, guard == null ? NashornGuards.getFunctionGuard(this) : guard);
+
+        return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard);
    }
 
     /**
@@ -554,13 +540,50 @@
      * These don't want a callee parameter, so bind that. Name binding is optional.
      */
     MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
-        return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestInvoker(type)), bindName), type);
+        return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestInvoker(type, null)), bindName), type);
     }
 
     private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
         return bindName == null ? methodHandle : MH.insertArguments(methodHandle, 1, bindName);
     }
 
+    /**
+     * Get the guard that checks if a {@link ScriptFunction} is equal to
+     * a known ScriptFunction, using reference comparison
+     *
+     * @param function The ScriptFunction to check against. This will be bound to the guard method handle
+     *
+     * @return method handle for guard
+     */
+    private static MethodHandle getFunctionGuard(final ScriptFunction function) {
+        assert function.data != null;
+        return MH.insertArguments(IS_FUNCTION_MH, 1, function.data);
+    }
+
+    /**
+     * Get a guard that checks if a {@link ScriptFunction} is equal to
+     * a known ScriptFunction using reference comparison, and whether the type of
+     * the second argument (this-object) is not a JavaScript primitive type.
+     *
+     * @param function The ScriptFunction to check against. This will be bound to the guard method handle
+     *
+     * @return method handle for guard
+     */
+    private static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) {
+        assert function.data != null;
+        return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.data);
+    }
+
+    @SuppressWarnings("unused")
+    private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) {
+        return self instanceof ScriptFunction && ((ScriptFunction)self).data == data;
+    }
+
+    @SuppressWarnings("unused")
+    private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) {
+        return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
+    }
+
     private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) {
         final Class   own = ScriptFunction.class;
         final MethodType mt  = MH.type(rtype, types);
diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Thu Mar 21 10:43:41 2013 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Tue Mar 26 12:08:00 2013 -0700
@@ -32,227 +32,94 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
-import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.parser.Token;
-import jdk.nashorn.internal.parser.TokenType;
+
+import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
 
 /**
  * A container for data needed to instantiate a specific {@link ScriptFunction} at runtime.
  * Instances of this class are created during codegen and stored in script classes'
  * constants array to reduce function instantiation overhead during runtime.
  */
-public final class ScriptFunctionData {
-    private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
-    private static final MethodHandle NEWFILTER     = findOwnMH("newFilter", Object.class, Object.class, Object.class);
-
-    // per-function object flags
-    private static final int IS_STRICT      = 0b0000_0001;
-    private static final int IS_BUILTIN     = 0b0000_0010;
-    private static final int HAS_CALLEE     = 0b0000_0100;
-    private static final int IS_VARARGS     = 0b0000_1000;
-    private static final int IS_CONSTRUCTOR = 0b0001_0000;
+public abstract class ScriptFunctionData {
 
-    /** Name of the function or "" */
-    private final String name;
-    /** Source of this function, or null */
-    private final Source source;
-    /** Map for new instance constructor */
-    private PropertyMap  allocatorMap;
-    /** Start position and length in source */
-    private final long   token;
-    /** Number of expected arguments, either taken from FunctionNode or calculated from method handle signature*/
-    private int          arity;
-    private final int    flags;
+    /** Name of the function or "" for anonynous functions */
+    protected final String name;
+
+    /** All versions of this function that have been generated to code */
+    protected final CompiledFunctions code;
 
-    /** Reference to code for this method. */
-    private MethodHandle invoker;
-    /** Reference to code for this method when called to create "new" object. This must always be populated with a
-     * result of calling {@link #composeConstructor(MethodHandle)} on the value of the {@link #invoker} field. */
-    private MethodHandle constructor;
-    /** Constructor to create a new instance. */
-    private MethodHandle allocator;
-    /** Generic invoker to used in {@link ScriptFunction#invoke(Object, Object...)}. */
-    private MethodHandle genericInvoker;
-    /** Specializations - see @SpecializedFunction */
-    private MethodHandle[] invokeSpecializations;
-    /** Specializations - see @SpecializedFunction. Same restrictions as for {@link #constructor} apply; only populate
-     * with method handles returned from {@link #composeConstructor(MethodHandle)}. */
-    private MethodHandle[] constructSpecializations;
+    private int arity;
+
+    private final boolean isStrict;
 
-    /**
-     * Constructor
-     * @param fn the function node
-     * @param allocatorMap the allocator property map
-     */
-    public ScriptFunctionData(final FunctionNode fn, final PropertyMap allocatorMap) {
+    private final boolean isBuiltin;
 
-        final long firstToken = fn.getFirstToken();
-        final long lastToken  = fn.getLastToken();
-        final int  position   = Token.descPosition(firstToken);
-        final int  length     = Token.descPosition(lastToken) - position + Token.descLength(lastToken);
+    private final boolean isConstructor;
 
-        this.name         = fn.isAnonymous() ? "" : fn.getIdent().getName();
-        this.source       = fn.getSource();
-        this.allocatorMap = allocatorMap;
-        this.token        = Token.toDesc(TokenType.FUNCTION, position, length);
-        this.arity        = fn.getParameters().size();
-        this.flags        = makeFlags(fn.needsCallee(), fn.isVarArg(), fn.isStrictMode(), false, true);
-    }
+    private static final MethodHandle NEWFILTER     = findOwnMH("newFilter", Object.class, Object.class, Object.class);
+    private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
 
     /**
      * Constructor
      *
-     * @param name the function name
-     * @param methodHandle the method handle
-     * @param specs array of specialized method handles
-     * @param strict strict flag
-     * @param builtin builtin flag
-     * @param isConstructor constructor flags
+     * @param name          script function name
+     * @param arity         arity
+     * @param isStrict      is the function strict
+     * @param isBuiltin     is the function built in
+     * @param isConstructor is the function a constructor
      */
-    public ScriptFunctionData(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) {
-        this(name, null, 0L, methodHandle, specs, strict, builtin, isConstructor);
+    protected ScriptFunctionData(final String name, final int arity, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
+        this.name          = name;
+        this.arity         = arity;
+        this.code          = new CompiledFunctions();
+        this.isStrict      = isStrict;
+        this.isBuiltin     = isBuiltin;
+        this.isConstructor = isConstructor;
     }
 
-    private ScriptFunctionData(final String name, final Source source, final long token, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) {
-        this.name   = name;
-        this.source = source;
-        this.token  = token;
-
-        final boolean isVarArg = isVarArg(methodHandle);
-        final boolean needsCallee = needsCallee(methodHandle);
-
-        this.flags = makeFlags(needsCallee, isVarArg, strict, builtin, isConstructor);
-        int lArity = isVarArg ? -1 : methodHandle.type().parameterCount() - 1; //drop the self param for arity
-
-        if (needsCallee && !isVarArg) {
-            lArity--;
-        }
-
-        if (isConstructor(methodHandle)) {
-            assert isConstructor;
-            if (!isVarArg) {
-                lArity--;    // drop the boolean flag for arity
-            }
-            /*
-             * We insert a boolean argument to tell if the method was invoked as constructor or not if the method
-             * handle's first argument is boolean.
-             */
-            this.invoker     = MH.insertArguments(methodHandle, 0, false);
-            this.constructor = composeConstructor(MH.insertArguments(methodHandle, 0, true));
-
-            if (specs != null) {
-                this.invokeSpecializations    = new MethodHandle[specs.length];
-                this.constructSpecializations = new MethodHandle[specs.length];
-                for (int i = 0; i < specs.length; i++) {
-                    this.invokeSpecializations[i]    = MH.insertArguments(specs[i], 0, false);
-                    this.constructSpecializations[i] = composeConstructor(MH.insertArguments(specs[i], 0, true));
-                }
-            }
-        } else {
-            this.invoker                  = methodHandle;
-            this.constructor              = null; // delay composition of the constructor
-            this.invokeSpecializations    = specs;
-            this.constructSpecializations = null; // delay composition of the constructors
-        }
-        this.arity = lArity;
-    }
-
-    /**
-     * Get the arity of the function.
-     * @return the arity
-     */
-    int getArity() {
+    final int getArity() {
         return arity;
     }
 
     /**
-     * Set the arity of the function.
-     * @param arity the arity
+     * Used from e.g. Native*$Constructors as an explicit call. TODO - make arity immutable and final
+     * @param arity new arity
      */
-    void setArity(int arity) {
+    void setArity(final int arity) {
         this.arity = arity;
     }
 
-    /**
-     * Get the function name.
-     * @return function name
-     */
-    String getName() {
-        return name;
+    CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
+        final MethodHandle boundInvoker = bindInvokeHandle(originalInv.getInvoker(), fn, self, args);
+
+        if (isConstructor()) {
+            ensureConstructor(originalInv);
+            return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args));
+        }
+
+        return new CompiledFunction(boundInvoker);
     }
 
     /**
-     * Get this function as a String containing its source code. If no source code
-     * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
-     * @return string representation of this function's source
+     * Is this a ScriptFunction generated with strict semantics?
+     * @return true if strict, false otherwise
      */
-    String toSource() {
-        if (source != null && token != 0) {
-            return source.getString(Token.descPosition(token), Token.descLength(token));
-        }
-
-        return "function " + (name == null ? "" : name) + "() { [native code] }";
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder();
-
-        sb.append(super.toString())
-                .append(" [ ")
-                .append(invoker)
-                .append(", ")
-                .append((name == null || name.isEmpty()) ? "" : name);
-
-        if (source != null) {
-            sb.append(" @ ")
-                    .append(source.getName())
-                    .append(':')
-                    .append(source.getLine(Token.descPosition(token)));
-        }
-        sb.append(" ]");
-
-        return sb.toString();
+    public boolean isStrict() {
+        return isStrict;
     }
 
-    /**
-     * Returns true if the function needs a callee argument.
-     * @return the needsCallee flag
-     */
-    boolean needsCallee() {
-        return (flags & HAS_CALLEE) != 0;
-    }
-
-    /**
-     * Returns true if this is a strict-mode function.
-     * @return the strict flag
-     */
-    public boolean isStrict() {
-        return (flags & IS_STRICT) != 0;
+    boolean isBuiltin() {
+        return isBuiltin;
     }
 
-    /**
-     * Returns true if this is a built-in function.
-     * @return the built-in flag
-     */
-    private boolean isBuiltin() {
-        return (flags & IS_BUILTIN) != 0;
+    boolean isConstructor() {
+        return isConstructor;
     }
 
-    /**
-     * Returns true if this function can be used as a constructor.
-     * @return the constructor flag
-     */
-    private boolean isConstructor() {
-        return (flags & IS_CONSTRUCTOR) != 0;
-    }
-
-    /**
-     * Returns true if this is a var-arg function.
-     * @return the var-arg flag
-     */
-    private boolean isVarArg() {
-        return (flags & IS_VARARGS) != 0;
+    boolean needsCallee() {
+        // we don't know if we need a callee or not unless we are generated
+        ensureCodeGenerated();
+        return code.needsCallee();
     }
 
     /**
@@ -261,127 +128,408 @@
      * @return true if this argument must be an object
      */
     boolean needsWrappedThis() {
-        return (flags & (IS_STRICT | IS_BUILTIN)) == 0;
+        return !isStrict && !isBuiltin;
+    }
+
+    String toSource() {
+        return "function " + (name == null ? "" : name) + "() { [native code] }";
+    }
+
+    String getName() {
+        return name;
+    }
+
+    /**
+     * Get this function as a String containing its source code. If no source code
+     * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
+     *
+     * @return string representation of this function
+     */
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+
+        sb.append("name='").
+                append(name.isEmpty() ? "" : name).
+                append("' ").
+                append(code.size()).
+                append(" invokers=").
+                append(code);
+
+        return sb.toString();
     }
 
     /**
-     * Get the method handle used to invoke this function.
-     * @return the invoke handle
+     * Pick the best invoker, i.e. the one version of this method with as narrow and specific
+     * types as possible. If the call site arguments are objects, but boxed primitives we can
+     * also try to get a primitive version of the method and do an unboxing filter, but then
+     * we need to insert a guard that checks the argument is really always a boxed primitive
+     * and not suddenly a "real" object
+     *
+     * @param callSiteType callsite type
+     * @param args         arguments at callsite on first trampoline invocation
+     * @return method handle to best invoker
      */
-    MethodHandle getInvoker() {
-        return invoker;
+    MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
+        return getBest(callSiteType).getInvoker();
     }
 
-    MethodHandle getBestInvoker(final MethodType type) {
-        return SpecializedMethodChooser.candidateWithLowestWeight(type, invoker, invokeSpecializations);
+    MethodHandle getBestInvoker(final MethodType callSiteType) {
+        return getBestInvoker(callSiteType, null);
+    }
+
+    MethodHandle getBestConstructor(final MethodType callSiteType, final Object[] args) {
+        if (!isConstructor()) {
+            throw typeError("not.a.constructor", toSource());
+        }
+        ensureCodeGenerated();
+
+        final CompiledFunction best = getBest(callSiteType);
+        ensureConstructor(best);
+        return best.getConstructor();
+    }
+
+    MethodHandle getBestConstructor(final MethodType callSiteType) {
+        return getBestConstructor(callSiteType, null);
     }
 
     /**
-     * Get the method handle used to invoke this function as a constructor.
-     * @return the constructor handle
+     * Subclass responsibility. If we can have lazy code generation, this is a hook to ensure that
+     * code exists before performing an operation.
      */
-    private MethodHandle getConstructor() {
-        if (constructor == null) {
-            constructor = composeConstructor(invoker);
-        }
+    protected void ensureCodeGenerated() {
+        //empty
+    }
 
-        return constructor;
+    /**
+     * Return a generic Object/Object invoker for this method. It will ensure code
+     * is generated, get the most generic of all versions of this function and adapt it
+     * to Objects.
+     *
+     * TODO this is only public because {@link JavaAdapterFactory} can't supply us with
+     * a MethodType that we can use for lookup due to boostrapping problems. Can be fixed
+     *
+     * @return generic invoker of this script function
+     */
+    public final MethodHandle getGenericInvoker() {
+        ensureCodeGenerated();
+        return composeGenericMethod(code.mostGeneric().getInvoker());
+    }
+
+    private CompiledFunction getBest(final MethodType callSiteType) {
+        ensureCodeGenerated();
+        return code.best(callSiteType);
     }
 
-    MethodHandle getBestConstructor(MethodType descType) {
-        if (!isConstructor()) {
-            throw typeError("not.a.constructor", toSource());
-        }
-        return SpecializedMethodChooser.candidateWithLowestWeight(descType, getConstructor(), getConstructSpecializations());
+    /**
+     * Allocates an object using this function's allocator.
+     * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator.
+     */
+    ScriptObject allocate() {
+        return null;
     }
 
-    private MethodHandle composeConstructor(MethodHandle ctor) {
+    /**
+     * This method is used to create the immutable portion of a bound function.
+     * See {@link ScriptFunction#makeBoundFunction(Object, Object[])}
+     *
+     * @param fn the original function being bound
+     * @param self this reference to bind. Can be null.
+     * @param args additional arguments to bind. Can be null.
+     */
+    ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) {
+        ensureCodeGenerated();
+
+        final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
+        final int length = args == null ? 0 : args.length;
+
+        CompiledFunctions boundList = new CompiledFunctions();
+        for (final CompiledFunction inv : code) {
+            boundList.add(bind(inv, fn, self, allArgs));
+        }
+        ScriptFunctionData boundData = new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, isStrict(), isBuiltin(), isConstructor());
+        return boundData;
+    }
+
+    /**
+     * Compose a constructor given a primordial constructor handle
+     *
+     * @param ctor         primordial constructor handle
+     * @param needsCallee  do we need to pass a callee
+     *
+     * @return the composed constructor
+     */
+    protected MethodHandle composeConstructor(final MethodHandle ctor, final boolean needsCallee) {
         // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having
         // "this" in the first argument position is what allows the elegant folded composition of
         // (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor
         // always returns Object.
-        MethodHandle composedCtor = changeReturnTypeToObject(swapCalleeAndThis(ctor));
+        MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor;
+
+        composedCtor = changeReturnTypeToObject(composedCtor);
 
         final MethodType ctorType = composedCtor.type();
+
         // Construct a dropping type list for NEWFILTER, but don't include constructor "this" into it, so it's actually
         // captured as "allocation" parameter of NEWFILTER after we fold the constructor into it.
         // (this, [callee, ]args...) => ([callee, ]args...)
         final Class[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray();
+
         // Fold constructor into newFilter that replaces the return value from the constructor with the originally
         // allocated value when the originally allocated value is a primitive.
         // (result, this, [callee, ]args...) x (this, [callee, ]args...) => (this, [callee, ]args...)
         composedCtor = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), composedCtor);
 
         // allocate() takes a ScriptFunction and returns a newly allocated ScriptObject...
-        if (needsCallee()) {
+        if (needsCallee) {
             // ...we either fold it into the previous composition, if we need both the ScriptFunction callee object and
             // the newly allocated object in the arguments, so (this, callee, args...) x (callee) => (callee, args...),
             // or...
             return MH.foldArguments(composedCtor, ScriptFunction.ALLOCATE);
         }
+
         // ...replace the ScriptFunction argument with the newly allocated object, if it doesn't need the callee
         // (this, args...) filter (callee) => (callee, args...)
         return MH.filterArguments(composedCtor, 0, ScriptFunction.ALLOCATE);
     }
 
     /**
-     * Get an adapted version of the invoker handle that only uses {@code Object} as parameter and return types.
-     * @return the generic invoke handle
+     * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed
+     * method handle. If this function's method handles don't need a callee parameter, returns the original method
+     * handle unchanged.
+     *
+     * @param mh a method handle with order of arguments {@code (callee, this, args...)}
+     *
+     * @return a method handle with order of arguments {@code (this, callee, args...)}
+     */
+    private static MethodHandle swapCalleeAndThis(final MethodHandle mh) {
+        final MethodType type = mh.type();
+        assert type.parameterType(0) == ScriptFunction.class : type;
+        assert type.parameterType(1) == Object.class : type;
+        final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class);
+        final int[] reorder = new int[type.parameterCount()];
+        reorder[0] = 1;
+        assert reorder[1] == 0;
+        for (int i = 2; i < reorder.length; ++i) {
+            reorder[i] = i;
+        }
+        return MethodHandles.permuteArguments(mh, newType, reorder);
+    }
+
+    /**
+     * Convert this argument for non-strict functions according to ES 10.4.3
+     *
+     * @param thiz the this argument
+     *
+     * @return the converted this object
+     */
+    private Object convertThisObject(final Object thiz) {
+        if (!(thiz instanceof ScriptObject) && needsWrappedThis()) {
+            if (JSType.nullOrUndefined(thiz)) {
+                return Context.getGlobalTrusted();
+            }
+
+            if (isPrimitiveThis(thiz)) {
+                return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz);
+            }
+        }
+
+        return thiz;
+    }
+
+    static boolean isPrimitiveThis(final Object obj) {
+        return obj instanceof String || obj instanceof ConsString ||
+               obj instanceof Number || obj instanceof Boolean;
+    }
+
+    /**
+     * Creates an invoker method handle for a bound function.
+     *
+     * @param targetFn the function being bound
+     * @param originalInvoker an original invoker method handle for the function. This can be its generic invoker or
+     * any of its specializations.
+     * @param self the "this" value being bound
+     * @param args additional arguments being bound
+     *
+     * @return a bound invoker method handle that will bind the self value and the specified arguments. The resulting
+     * invoker never needs a callee; if the original invoker needed it, it will be bound to {@code fn}. The resulting
+     * invoker still takes an initial {@code this} parameter, but it is always dropped and the bound {@code self} passed
+     * to the original invoker on invocation.
      */
-    private MethodHandle getGenericInvoker() {
-        if (genericInvoker == null) {
-            assert invoker != null : "invoker is null";
-            genericInvoker = makeGenericMethod(invoker);
+    private MethodHandle bindInvokeHandle(final MethodHandle originalInvoker, final ScriptFunction targetFn, final Object self, final Object[] args) {
+        // Is the target already bound? If it is, we won't bother binding either callee or self as they're already bound
+        // in the target and will be ignored anyway.
+        final boolean isTargetBound = targetFn.isBoundFunction();
+
+        final boolean needsCallee = needsCallee(originalInvoker);
+        assert needsCallee == needsCallee() : "callee contract violation 2";
+        assert !(isTargetBound && needsCallee); // already bound functions don't need a callee
+
+        final Object boundSelf = isTargetBound ? null : convertThisObject(self);
+        final MethodHandle boundInvoker;
+
+        if (isVarArg(originalInvoker)) {
+            // First, bind callee and this without arguments
+            final MethodHandle noArgBoundInvoker;
+
+            if (isTargetBound) {
+                // Don't bind either callee or this
+                noArgBoundInvoker = originalInvoker;
+            } else if (needsCallee) {
+                // Bind callee and this
+                noArgBoundInvoker = MH.insertArguments(originalInvoker, 0, targetFn, boundSelf);
+            } else {
+                // Only bind this
+                noArgBoundInvoker = MH.bindTo(originalInvoker, boundSelf);
+            }
+            // Now bind arguments
+            if (args.length > 0) {
+                boundInvoker = varArgBinder(noArgBoundInvoker, args);
+            } else {
+                boundInvoker = noArgBoundInvoker;
+            }
+        } else {
+            final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount(), args.length + (isTargetBound ? 0 : (needsCallee  ? 2 : 1)))];
+            int next = 0;
+            if (!isTargetBound) {
+                if (needsCallee) {
+                    boundArgs[next++] = targetFn;
+                }
+                boundArgs[next++] = boundSelf;
+            }
+            // If more bound args were specified than the function can take, we'll just drop those.
+            System.arraycopy(args, 0, boundArgs, next, boundArgs.length - next);
+            // If target is already bound, insert additional bound arguments after "this" argument, at position 1;
+            // "this" will get dropped anyway by the target invoker. We previously asserted that already bound functions
+            // don't take a callee parameter, so we can know that the signature is (this[, args...]) therefore args
+            // start at position 1. If the function is not bound, we start inserting arguments at position 0.
+            boundInvoker = MH.insertArguments(originalInvoker, isTargetBound ? 1 : 0, boundArgs);
+        }
+
+        if (isTargetBound) {
+            return boundInvoker;
         }
-        return genericInvoker;
+
+        // If the target is not already bound, add a dropArguments that'll throw away the passed this
+        return MH.dropArguments(boundInvoker, 0, Object.class);
+    }
+
+    /**
+     * Creates a constructor method handle for a bound function using the passed constructor handle.
+     *
+     * @param originalConstructor the constructor handle to bind. It must be a composed constructor.
+     * @param fn the function being bound
+     * @param args arguments being bound
+     *
+     * @return a bound constructor method handle that will bind the specified arguments. The resulting constructor never
+     * needs a callee; if the original constructor needed it, it will be bound to {@code fn}. The resulting constructor
+     * still takes an initial {@code this} parameter and passes it to the underlying original constructor. Finally, if
+     * this script function data object has no constructor handle, null is returned.
+     */
+    private static MethodHandle bindConstructHandle(final MethodHandle originalConstructor, final ScriptFunction fn, final Object[] args) {
+        assert originalConstructor != null;
+
+        // If target function is already bound, don't bother binding the callee.
+        final MethodHandle calleeBoundConstructor = fn.isBoundFunction() ? originalConstructor :
+            MH.dropArguments(MH.bindTo(originalConstructor, fn), 0, ScriptFunction.class);
+
+        if (args.length == 0) {
+            return calleeBoundConstructor;
+        }
+
+        if (isVarArg(calleeBoundConstructor)) {
+            return varArgBinder(calleeBoundConstructor, args);
+        }
+
+        final Object[] boundArgs;
+
+        final int maxArgCount = calleeBoundConstructor.type().parameterCount() - 1;
+        if (args.length <= maxArgCount) {
+            boundArgs = args;
+        } else {
+            boundArgs = new Object[maxArgCount];
+            System.arraycopy(args, 0, boundArgs, 0, maxArgCount);
+        }
+
+        return MH.insertArguments(calleeBoundConstructor, 1, boundArgs);
+    }
+
+    /**
+     * Takes a method handle, and returns a potentially different method handle that can be used in
+     * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}.
+     * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into
+     * {@code Object} as well, except for the following ones:
+     * 
    + *
  • a last parameter of type {@code Object[]} which is used for vararg functions,
  • + *
  • the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself + * (callee) as an argument.
  • + *
+ * + * @param mh the original method handle + * + * @return the new handle, conforming to the rules above. + */ + protected MethodHandle composeGenericMethod(final MethodHandle mh) { + final MethodType type = mh.type(); + MethodType newType = type.generic(); + if (isVarArg(mh)) { + newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class); + } + if (needsCallee(mh)) { + newType = newType.changeParameterType(0, ScriptFunction.class); + } + return type.equals(newType) ? mh : mh.asType(newType); } /** * Execute this script function. + * * @param self Target object. * @param arguments Call arguments. * @return ScriptFunction result. + * * @throws Throwable if there is an exception/error with the invocation or thrown from it */ Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable { - final MethodHandle genInvoker = getGenericInvoker(); - final Object selfObj = convertThisObject(self); - final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; + final MethodHandle mh = getGenericInvoker(); + + final Object selfObj = convertThisObject(self); + final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; - if (isVarArg()) { - if (needsCallee()) { - return genInvoker.invokeExact(fn, selfObj, args); + if (isVarArg(mh)) { + if (needsCallee(mh)) { + return mh.invokeExact(fn, selfObj, args); } - return genInvoker.invokeExact(selfObj, args); + return mh.invokeExact(selfObj, args); } - final int paramCount = genInvoker.type().parameterCount(); - if (needsCallee()) { + final int paramCount = mh.type().parameterCount(); + if (needsCallee(mh)) { switch (paramCount) { case 2: - return genInvoker.invokeExact(fn, selfObj); + return mh.invokeExact(fn, selfObj); case 3: - return genInvoker.invokeExact(fn, selfObj, getArg(args, 0)); + return mh.invokeExact(fn, selfObj, getArg(args, 0)); case 4: - return genInvoker.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1)); + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1)); case 5: - return genInvoker.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); default: - return genInvoker.invokeWithArguments(withArguments(fn, selfObj, paramCount, args)); + return mh.invokeWithArguments(withArguments(fn, selfObj, paramCount, args)); } } switch (paramCount) { case 1: - return genInvoker.invokeExact(selfObj); + return mh.invokeExact(selfObj); case 2: - return genInvoker.invokeExact(selfObj, getArg(args, 0)); + return mh.invokeExact(selfObj, getArg(args, 0)); case 3: - return genInvoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); case 4: - return genInvoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); default: - return genInvoker.invokeWithArguments(withArguments(null, selfObj, paramCount, args)); + return mh.invokeWithArguments(withArguments(null, selfObj, paramCount, args)); } } @@ -389,15 +537,13 @@ return i < args.length ? args[i] : UNDEFINED; } - private Object[] withArguments(final ScriptFunction fn, final Object self, final int argCount, final Object[] args) { + private static Object[] withArguments(final ScriptFunction fn, final Object self, final int argCount, final Object[] args) { final Object[] finalArgs = new Object[argCount]; int nextArg = 0; - if (needsCallee()) { - assert fn != null; + if (fn != null) { + //needs callee finalArgs[nextArg++] = fn; - } else { - assert fn == null; } finalArgs[nextArg++] = self; @@ -413,255 +559,14 @@ return finalArgs; } - - /** - * Get the specialized construct handles for this function. - * @return array of specialized construct handles - */ - private MethodHandle[] getConstructSpecializations() { - if(constructSpecializations == null && invokeSpecializations != null) { - final MethodHandle[] ctors = new MethodHandle[invokeSpecializations.length]; - for(int i = 0; i < ctors.length; ++i) { - ctors[i] = composeConstructor(invokeSpecializations[i]); - } - constructSpecializations = ctors; - } - return constructSpecializations; - } - - /** - * Set the method handles for this function. - * @param invoker the invoker handle - * @param allocator the allocator handle - */ - public void setMethodHandles(final MethodHandle invoker, final MethodHandle allocator) { - // We can't make method handle fields final because they're not available during codegen - // and they're set when first called, so we enforce set-once here. - if (this.invoker == null) { - this.invoker = invoker; - this.constructor = null; // delay constructor composition - this.allocator = allocator; - } - } - - /** - * Used by the trampoline. Must not be any wider than package - * private - * @param invoker new invoker - */ - void resetInvoker(final MethodHandle invoker) { - this.invoker = invoker; - this.constructor = null; //delay constructor composition - } - - /** - * Allocates an object using this function's allocator. - * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator. - */ - ScriptObject allocate() { - if (allocator == null) { - return null; - } - - try { - return (ScriptObject)allocator.invokeExact(allocatorMap); - } catch (final RuntimeException | Error e) { - throw e; - } catch (final Throwable t) { - throw new RuntimeException(t); - } - } - - /** - * This method is used to create the immutable portion of a bound function. - * See {@link ScriptFunction#makeBoundFunction(Object, Object[])} - * - * @param fn the original function being bound - * @param self this reference to bind. Can be null. - * @param args additional arguments to bind. Can be null. - */ - ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) { - final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args; - - final boolean isConstructor = isConstructor(); - // Note that the new ScriptFunctionData's method handle will not need a callee regardless of whether the - // original did. - final ScriptFunctionData boundData = new ScriptFunctionData(name, source, token, - bindInvokeHandle(invoker, fn, self, allArgs), bindInvokeSpecializations(fn, self, allArgs), isStrict(), isBuiltin(), isConstructor); - if(isConstructor) { - // Can't just rely on bound invoke as a basis for constructor, as it ignores the passed "this" in favor of the - // bound "this"; constructor on the other hand must see the actual "this" received from the allocator. - - // Binding a function will force constructor composition in getConstructor(); not really any way around that - // as it's the composed constructor that has to be bound to the function. - boundData.constructor = bindConstructHandle(getConstructor(), fn, allArgs); - boundData.constructSpecializations = bindConstructorSpecializations(fn, allArgs); - } - assert boundData.allocator == null; - final int thisArity = getArity(); - if(thisArity != -1) { - boundData.setArity(Math.max(0, thisArity - args.length)); - } else { - assert boundData.getArity() == -1; - } - return boundData; - } - - /** - * Convert this argument for non-strict functions according to ES 10.4.3 - * - * @param thiz the this argument - * - * @return the converted this object - */ - Object convertThisObject(final Object thiz) { - if (!(thiz instanceof ScriptObject) && needsWrappedThis()) { - if (JSType.nullOrUndefined(thiz)) { - return Context.getGlobalTrusted(); - } - - if (isPrimitiveThis(thiz)) { - return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz); - } - } - - return thiz; - } - - static boolean isPrimitiveThis(Object obj) { - return obj instanceof String || obj instanceof ConsString || - obj instanceof Number || obj instanceof Boolean; - } - - /** - * Creates an invoker method handle for a bound function. - * @param targetFn the function being bound - * @param originalInvoker an original invoker method handle for the function. This can be its generic invoker or - * any of its specializations. - * @param self the "this" value being bound - * @param args additional arguments being bound - * @return a bound invoker method handle that will bind the self value and the specified arguments. The resulting - * invoker never needs a callee; if the original invoker needed it, it will be bound to {@code fn}. The resulting - * invoker still takes an initial {@code this} parameter, but it is always dropped and the bound {@code self} passed - * to the original invoker on invocation. - */ - private MethodHandle bindInvokeHandle(final MethodHandle originalInvoker, final ScriptFunction targetFn, final Object self, final Object[] args) { - // Is the target already bound? If it is, we won't bother binding either callee or self as they're already bound - // in the target and will be ignored anyway. - final boolean isTargetBound = targetFn.isBoundFunction(); - assert !(isTargetBound && needsCallee()); // already bound functions don't need a callee - final Object boundSelf = isTargetBound ? null : convertThisObject(self); - final MethodHandle boundInvoker; - if(isVarArg(originalInvoker)) { - // First, bind callee and this without arguments - final MethodHandle noArgBoundInvoker; - if(isTargetBound) { - // Don't bind either callee or this - noArgBoundInvoker = originalInvoker; - } else if(needsCallee()) { - // Bind callee and this - noArgBoundInvoker = MH.insertArguments(originalInvoker, 0, targetFn, boundSelf); - } else { - // Only bind this - noArgBoundInvoker = MH.bindTo(originalInvoker, boundSelf); - } - // Now bind arguments - if(args.length > 0) { - boundInvoker = varArgBinder(noArgBoundInvoker, args); - } else { - boundInvoker = noArgBoundInvoker; - } - } else { - final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount(), - args.length + (isTargetBound ? 0 : (needsCallee() ? 2 : 1)))]; - int next = 0; - if(!isTargetBound) { - if(needsCallee()) { - boundArgs[next++] = targetFn; - } - boundArgs[next++] = boundSelf; - } - // If more bound args were specified than the function can take, we'll just drop those. - System.arraycopy(args, 0, boundArgs, next, boundArgs.length - next); - // If target is already bound, insert additional bound arguments after "this" argument, at position 1; - // "this" will get dropped anyway by the target invoker. We previously asserted that already bound functions - // don't take a callee parameter, so we can know that the signature is (this[, args...]) therefore args - // start at position 1. If the function is not bound, we start inserting arguments at position 0. - boundInvoker = MH.insertArguments(originalInvoker, isTargetBound ? 1 : 0, boundArgs); - } - if(isTargetBound) { - return boundInvoker; - } - // If the target is not already bound, add a dropArguments that'll throw away the passed this - return MH.dropArguments(boundInvoker, 0, Object.class); - } - - private MethodHandle[] bindInvokeSpecializations(final ScriptFunction fn, final Object self, final Object[] args) { - if(invokeSpecializations == null) { - return null; - } - final MethodHandle[] boundSpecializations = new MethodHandle[invokeSpecializations.length]; - for(int i = 0; i < invokeSpecializations.length; ++i) { - boundSpecializations[i] = bindInvokeHandle(invokeSpecializations[i], fn, self, args); - } - return boundSpecializations; - } - - /** - * Creates a constructor method handle for a bound function using the passed constructor handle. - * @param originalConstructor the constructor handle to bind. It must be a composed constructor. - * @param fn the function being bound - * @param args arguments being bound - * @return a bound constructor method handle that will bind the specified arguments. The resulting constructor never - * needs a callee; if the original constructor needed it, it will be bound to {@code fn}. The resulting constructor - * still takes an initial {@code this} parameter and passes it to the underlying original constructor. Finally, if - * this script function data object has no constructor handle, null is returned. - */ - private static MethodHandle bindConstructHandle(final MethodHandle originalConstructor, final ScriptFunction fn, final Object[] args) { - if(originalConstructor == null) { - return null; - } - - // If target function is already bound, don't bother binding the callee. - final MethodHandle calleeBoundConstructor = fn.isBoundFunction() ? originalConstructor : - MH.dropArguments(MH.bindTo(originalConstructor, fn), 0, ScriptFunction.class); - if(args.length == 0) { - return calleeBoundConstructor; - } - - if(isVarArg(calleeBoundConstructor)) { - return varArgBinder(calleeBoundConstructor, args); - } - - final Object[] boundArgs; - final int maxArgCount = calleeBoundConstructor.type().parameterCount() - 1; - if (args.length <= maxArgCount) { - boundArgs = args; - } else { - boundArgs = new Object[maxArgCount]; - System.arraycopy(args, 0, boundArgs, 0, maxArgCount); - } - return MH.insertArguments(calleeBoundConstructor, 1, boundArgs); - } - - private MethodHandle[] bindConstructorSpecializations(final ScriptFunction fn, final Object[] args) { - final MethodHandle[] ctorSpecs = getConstructSpecializations(); - if(ctorSpecs == null) { - return null; - } - final MethodHandle[] boundSpecializations = new MethodHandle[ctorSpecs.length]; - for(int i = 0; i < ctorSpecs.length; ++i) { - boundSpecializations[i] = bindConstructHandle(ctorSpecs[i], fn, args); - } - return boundSpecializations; - } - /** * Takes a variable-arity method and binds a variable number of arguments in it. The returned method will filter the * vararg array and pass a different array that prepends the bound arguments in front of the arguments passed on * invocation + * * @param mh the handle * @param args the bound arguments + * * @return the bound method handle */ private static MethodHandle varArgBinder(final MethodHandle mh, final Object[] args) { @@ -671,41 +576,20 @@ } /** - * Convert boolean flags to int. - * @param needsCallee needs-callee flag - * @param isVarArg var-arg flag - * @param isStrict strict flag - * @param isBuiltin builtin flag - * @return int flags + * Adapts the method handle so its return type is {@code Object}. If the handle's return type is already + * {@code Object}, the handle is returned unchanged. + * + * @param mh the handle to adapt + * @return the adapted handle */ - private static int makeFlags(final boolean needsCallee, final boolean isVarArg, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { - int flags = 0; - if (needsCallee) { - flags |= HAS_CALLEE; - } - if (isVarArg) { - flags |= IS_VARARGS; - } - if (isStrict) { - flags |= IS_STRICT; - } - if (isBuiltin) { - flags |= IS_BUILTIN; - } - if (isConstructor) { - flags |= IS_CONSTRUCTOR; - } - - return flags; + private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) { + return MH.asType(mh, mh.type().changeReturnType(Object.class)); } - /** - * Test if a methodHandle refers to a constructor. - * @param methodHandle MethodHandle to test. - * @return True if method is a constructor. - */ - private static boolean isConstructor(final MethodHandle methodHandle) { - return methodHandle.type().parameterCount() >= 1 && methodHandle.type().parameterType(0) == boolean.class; + private void ensureConstructor(final CompiledFunction inv) { + if (!inv.hasConstructor()) { + inv.setConstructor(composeConstructor(inv.getInvoker(), needsCallee(inv.getInvoker()))); + } } /** @@ -713,102 +597,56 @@ * {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore - * they also always receive a callee. - * @param methodHandle the examined method handle + * they also always receive a callee). + * + * @param mh the examined method handle + * * @return true if the method handle expects a callee, false otherwise */ - private static boolean needsCallee(MethodHandle methodHandle) { - final MethodType type = methodHandle.type(); - final int len = type.parameterCount(); - if(len == 0) { + protected static boolean needsCallee(final MethodHandle mh) { + final MethodType type = mh.type(); + final int length = type.parameterCount(); + + if (length == 0) { return false; } - if(type.parameterType(0) == boolean.class) { - return len > 1 && type.parameterType(1) == ScriptFunction.class; + + if (type.parameterType(0) == boolean.class) { + return length > 1 && type.parameterType(1) == ScriptFunction.class; } + return type.parameterType(0) == ScriptFunction.class; } - private static boolean isVarArg(MethodHandle methodHandle) { - final MethodType type = methodHandle.type(); - return type.parameterType(type.parameterCount() - 1).isArray(); - } - /** - * Takes a method handle, and returns a potentially different method handle that can be used in - * {@link ScriptFunction#invoke(Object, Object...)} or {@link ScriptFunction#construct(Object, Object...)}. - * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into - * {@code Object} as well, except for the following ones: - *
    - *
  • a last parameter of type {@code Object[]} which is used for vararg functions,
  • - *
  • the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself - * (callee) as an argument.
  • - *
+ * Check if a javascript function methodhandle is a vararg handle * - * @param handle the original method handle - * @return the new handle, conforming to the rules above. + * @param mh method handle to check + * + * @return true if vararg */ - private MethodHandle makeGenericMethod(final MethodHandle handle) { - final MethodType type = handle.type(); - MethodType newType = type.generic(); - if (isVarArg()) { - newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class); - } - if (needsCallee()) { - newType = newType.changeParameterType(0, ScriptFunction.class); - } - return type.equals(newType) ? handle : handle.asType(newType); - } - - /** - * Adapts the method handle so its return type is {@code Object}. If the handle's return type is already - * {@code Object}, the handle is returned unchanged. - * @param mh the handle to adapt - * @return the adapted handle - */ - private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) { - return MH.asType(mh, mh.type().changeReturnType(Object.class)); - } - - - /** - * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed - * method handle. If this function's method handles don't need a callee parameter, returns the original method - * handle unchanged. - * @param mh a method handle with order of arguments {@code (callee, this, args...)} - * @return a method handle with order of arguments {@code (this, callee, args...)} - */ - private MethodHandle swapCalleeAndThis(final MethodHandle mh) { - if (!needsCallee()) { - return mh; - } + protected static boolean isVarArg(final MethodHandle mh) { final MethodType type = mh.type(); - assert type.parameterType(0) == ScriptFunction.class; - assert type.parameterType(1) == Object.class; - final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class); - final int[] reorder = new int[type.parameterCount()]; - reorder[0] = 1; - assert reorder[1] == 0; - for (int i = 2; i < reorder.length; ++i) { - reorder[i] = i; - } - return MethodHandles.permuteArguments(mh, newType, reorder); + return type.parameterType(type.parameterCount() - 1).isArray(); } @SuppressWarnings("unused") private static Object[] bindVarArgs(final Object[] array1, final Object[] array2) { - if(array2 == null) { + if (array2 == null) { // Must clone it, as we can't allow the receiving method to alter the array return array1.clone(); } + final int l2 = array2.length; - if(l2 == 0) { + if (l2 == 0) { return array1.clone(); } + final int l1 = array1.length; final Object[] concat = new Object[l1 + l2]; System.arraycopy(array1, 0, concat, 0, l1); System.arraycopy(array2, 0, concat, l1, l2); + return concat; } @@ -820,5 +658,4 @@ private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { return MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, name, MH.type(rtype, types)); } - } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/ScriptLoader.java --- a/src/jdk/nashorn/internal/runtime/ScriptLoader.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/ScriptLoader.java Tue Mar 26 12:08:00 2013 -0700 @@ -26,6 +26,7 @@ package jdk.nashorn.internal.runtime; import java.security.CodeSource; +import java.security.ProtectionDomain; /** * Responsible for loading script generated classes. @@ -57,6 +58,9 @@ * @return Installed class. */ synchronized Class installClass(final String name, final byte[] data, final CodeSource cs) { + if (cs == null) { + return defineClass(name, data, 0, data.length, new ProtectionDomain(null, getPermissions(null))); + } return defineClass(name, data, 0, data.length, cs); } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java --- a/src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.runtime; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; -import jdk.nashorn.internal.codegen.types.Type; -import jdk.nashorn.internal.runtime.options.Options; - -class SpecializedMethodChooser { - /** Should specialized function and specialized constructors for the builtin be used if available? */ - private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable"); - - static MethodHandle candidateWithLowestWeight(final MethodType descType, final MethodHandle initialCandidate, final MethodHandle[] specs) { - if (DISABLE_SPECIALIZATION || specs == null) { - return initialCandidate; - } - - int minimumWeight = Integer.MAX_VALUE; - MethodHandle candidate = initialCandidate; - - for (final MethodHandle spec : specs) { - final MethodType specType = spec.type(); - - if (!typeCompatible(descType, specType)) { - continue; - } - - //return type is ok. we want a wider or equal one for our callsite. - final int specWeight = weigh(specType); - if (specWeight < minimumWeight) { - candidate = spec; - minimumWeight = specWeight; - } - } - - return candidate; - } - - private static boolean typeCompatible(final MethodType desc, final MethodType spec) { - //spec must fit in desc - final Class[] dparray = desc.parameterArray(); - final Class[] sparray = spec.parameterArray(); - - if (dparray.length != sparray.length) { - return false; - } - - for (int i = 0; i < dparray.length; i++) { - final Type dp = Type.typeFor(dparray[i]); - final Type sp = Type.typeFor(sparray[i]); - - if (dp.isBoolean()) { - return false; //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution - } - - //specialization arguments must be at least as wide as dp, if not wider - if (Type.widest(dp, sp) != sp) { - //e.g. specialization takes double and callsite says "object". reject. - //but if specialization says double and callsite says "int" or "long" or "double", that's fine - return false; - } - } - - return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic. - } - - private static int weigh(final MethodType t) { - int weight = Type.typeFor(t.returnType()).getWeight(); - for (final Class paramType : t.parameterArray()) { - final int pweight = Type.typeFor(paramType).getWeight(); - weight += pweight; - } - return weight; - } -} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/StructureLoader.java --- a/src/jdk/nashorn/internal/runtime/StructureLoader.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/StructureLoader.java Tue Mar 26 12:08:00 2013 -0700 @@ -38,6 +38,7 @@ import java.security.CodeSource; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.security.ProtectionDomain; import jdk.nashorn.internal.codegen.ObjectClassGenerator; /** @@ -129,6 +130,6 @@ } final byte[] code = new ObjectClassGenerator(context).generate(descriptor); - return defineClass(name, code, 0, code.length); + return defineClass(name, code, 0, code.length, new ProtectionDomain(null, getPermissions(null))); } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/linker/Bootstrap.java --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Tue Mar 26 12:08:00 2013 -0700 @@ -57,7 +57,7 @@ static { final DynamicLinkerFactory factory = new DynamicLinkerFactory(); factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(), - new JSObjectLinker()); + new JSObjectLinker(), new ReflectionCheckLinker()); factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker()); factory.setSyncOnRelink(true); final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Tue Mar 26 12:08:00 2013 -0700 @@ -54,6 +54,7 @@ import java.security.CodeSource; import java.security.Permissions; import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; import java.security.SecureClassLoader; import java.security.SecureRandom; @@ -410,9 +411,14 @@ */ public static MethodHandle getConstructor(final Class sourceType, final Class targetType) throws Exception { final StaticClass adapterClass = getAdapterClassFor(new Class[] { targetType }); - return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl(NashornCallSiteDescriptor.get( - "dyn:new", MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false, - adapterClass, null)).getInvocation(), adapterClass); + return AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public MethodHandle run() throws Exception { + return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl(NashornCallSiteDescriptor.get( + "dyn:new", MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false, + adapterClass, null)).getInvocation(), adapterClass); + } + }); } /** @@ -456,9 +462,26 @@ private static ClassLoader createClassLoader(final ClassLoader parentLoader, final String className, final byte[] classBytes, final String privilegedActionClassName) { return new AdapterLoader(parentLoader) { + private final ClassLoader myLoader = getClass().getClassLoader(); private final ProtectionDomain myProtectionDomain = getClass().getProtectionDomain(); @Override + public Class loadClass(final String name, final boolean resolve) throws ClassNotFoundException { + try { + return super.loadClass(name, resolve); + } catch (final SecurityException se) { + // we may be implementing an interface or extending a class that was + // loaded by a loader that prevents package.access. If so, it'd throw + // SecurityException for nashorn's classes!. For adapter's to work, we + // should be able to refer to nashorn classes. + if (name.startsWith("jdk.nashorn.internal.")) { + return myLoader.loadClass(name); + } + throw se; + } + } + + @Override protected Class findClass(final String name) throws ClassNotFoundException { if(name.equals(className)) { final byte[] bytes = classBytes; diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java --- a/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java Tue Mar 26 12:08:00 2013 -0700 @@ -39,7 +39,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; /** - * Utility class shared by {@link NashornLinker} and {@code NashornPrimitiveLinker} for converting JS values to Java + * Utility class shared by {@code NashornLinker} and {@code NashornPrimitiveLinker} for converting JS values to Java * types. */ public class JavaArgumentConverters { diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/linker/NashornGuards.java --- a/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java Tue Mar 26 12:08:00 2013 -0700 @@ -40,8 +40,6 @@ private static final MethodHandle IS_SCRIPTOBJECT = findOwnMH("isScriptObject", boolean.class, Object.class); private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class); private static final MethodHandle IS_MAP = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class); - private static final MethodHandle IS_FUNCTION_MH = findOwnMH("isFunctionMH", boolean.class, Object.class, MethodHandle.class); - private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, MethodHandle.class); private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class); // don't create me! @@ -87,33 +85,6 @@ return MH.insertArguments(IS_INSTANCEOF_2, 1, class1, class2); } - /** - * Get the guard that checks if a {@link ScriptFunction} is equal to - * a known ScriptFunction, using reference comparison - * - * @param function The ScriptFunction to check against. This will be bound to the guard method handle - * - * @return method handle for guard - */ - public static MethodHandle getFunctionGuard(final ScriptFunction function) { - assert function.getInvokeHandle() != null; - return MH.insertArguments(IS_FUNCTION_MH, 1, function.getInvokeHandle()); - } - - /** - * Get a guard that checks if a {@link ScriptFunction} is equal to - * a known ScriptFunction using reference comparison, and whether the type of - * the second argument (this-object) is not a JavaScript primitive type. - * - * @param function The ScriptFunction to check against. This will be bound to the guard method handle - * - * @return method handle for guard - */ - public static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) { - assert function.getInvokeHandle() != null; - return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.getInvokeHandle()); - } - @SuppressWarnings("unused") private static boolean isScriptObject(final Object self) { return self instanceof ScriptObject; @@ -130,16 +101,6 @@ } @SuppressWarnings("unused") - private static boolean isFunctionMH(final Object self, final MethodHandle mh) { - return self instanceof ScriptFunction && ((ScriptFunction)self).getInvokeHandle() == mh; - } - - @SuppressWarnings("unused") - private static boolean isNonStrictFunction(final Object self, final Object arg, final MethodHandle mh) { - return self instanceof ScriptFunction && ((ScriptFunction)self).getInvokeHandle() == mh && arg instanceof ScriptObject; - } - - @SuppressWarnings("unused") private static boolean isInstanceOf2(final Object self, final Class class1, final Class class2) { return class1.isInstance(self) || class2.isInstance(self); } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java --- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Tue Mar 26 12:08:00 2013 -0700 @@ -109,7 +109,6 @@ } return new GuardedInvocation(method, guard, link.getSwitchPoint()); } - assert desc.getNameTokenCount() <= 2; // Named operations would hit the return null after findProperty return null; } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,60 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.internal.runtime.linker; + +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; + +/** + * Check java reflection permission for java reflective and java.lang.invoke access from scripts + */ +final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{ + @Override + public boolean canLinkType(final Class type) { + return canLinkTypeStatic(type); + } + + private static boolean canLinkTypeStatic(final Class type) { + if (type == Class.class || ClassLoader.class.isAssignableFrom(type)) { + return true; + } + final String name = type.getName(); + return name.startsWith("java.lang.reflect.") || name.startsWith("java.lang.invoke."); + } + + @Override + public GuardedInvocation getGuardedInvocation(final LinkRequest origRequest, final LinkerServices linkerServices) + throws Exception { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("nashorn.JavaReflection")); + } + // let the next linker deal with actual linking + return null; + } +} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/options/OptionTemplate.java --- a/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java Tue Mar 26 12:08:00 2013 -0700 @@ -278,7 +278,7 @@ this.valueNextArg = Boolean.parseBoolean(arg); break; default: - throw new IllegalArgumentException(); + throw new IllegalArgumentException(keyToken); } } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/options/Options.java --- a/src/jdk/nashorn/internal/runtime/options/Options.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/options/Options.java Tue Mar 26 12:08:00 2013 -0700 @@ -66,6 +66,9 @@ /** The options map of enabled options */ private final TreeMap> options; + /** System property that can be used for command line option propagation */ + private static final String NASHORN_ARGS_PROPERTY = "nashorn.args"; + /** * Constructor * @@ -386,6 +389,14 @@ final LinkedList argList = new LinkedList<>(); Collections.addAll(argList, args); + final String extra = getStringProperty(NASHORN_ARGS_PROPERTY, null); + if (extra != null) { + final StringTokenizer st = new StringTokenizer(extra); + while (st.hasMoreTokens()) { + argList.add(st.nextToken()); + } + } + while (!argList.isEmpty()) { final String arg = argList.remove(0); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java --- a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java Tue Mar 26 12:08:00 2013 -0700 @@ -95,14 +95,14 @@ return null; // never matches or similar, e.g. a[] } - RegExpMatcher matcher = this.matcher; + RegExpMatcher currentMatcher = this.matcher; - if (matcher == null || matcher.getInput() != str) { - matcher = new DefaultMatcher(str); - this.matcher = matcher; + if (currentMatcher == null || matcher.getInput() != str) { + currentMatcher = new DefaultMatcher(str); + this.matcher = currentMatcher; } - return matcher; + return currentMatcher; } class DefaultMatcher implements RegExpMatcher { diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java --- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Tue Mar 26 12:08:00 2013 -0700 @@ -97,14 +97,14 @@ return null; } - RegExpMatcher matcher = this.matcher; + RegExpMatcher currentMatcher = this.matcher; - if (matcher == null || input != matcher.getInput()) { - matcher = new JoniMatcher(input); - this.matcher = matcher; + if (currentMatcher == null || input != currentMatcher.getInput()) { + currentMatcher = new JoniMatcher(input); + this.matcher = currentMatcher; } - return matcher; + return currentMatcher; } /** diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/regexp/RegExp.java --- a/src/jdk/nashorn/internal/runtime/regexp/RegExp.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExp.java Tue Mar 26 12:08:00 2013 -0700 @@ -156,7 +156,7 @@ * * @param key the message key * @param str string argument - * @throws jdk.nashorn.internal.runtime.ParserException + * @throws jdk.nashorn.internal.runtime.ParserException unconditionally */ protected static void throwParserException(final String key, final String str) throws ParserException { throw new ParserException(ECMAErrors.getMessage("parser.error.regex." + key, str)); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java --- a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Tue Mar 26 12:08:00 2013 -0700 @@ -25,7 +25,6 @@ package jdk.nashorn.internal.runtime.regexp; -import jdk.nashorn.internal.parser.Lexer; import jdk.nashorn.internal.runtime.ParserException; import jdk.nashorn.internal.runtime.options.Options; @@ -35,7 +34,6 @@ */ public class RegExpFactory { - private final static RegExpFactory instance; private final static String JDK = "jdk"; @@ -60,7 +58,8 @@ * Creates a Regular expression from the given {@code pattern} and {@code flags} strings. * * @param pattern RegExp pattern string - * @param flags RegExp flags string + * @param flags RegExp flags string + * @return new RegExp * @throws ParserException if flags is invalid or pattern string has syntax error. */ protected RegExp compile(final String pattern, final String flags) throws ParserException { @@ -71,8 +70,8 @@ * Compile a regexp with the given {@code source} and {@code flags}. * * @param pattern RegExp pattern string - * @param flags flag string - * + * @param flags flag string + * @return new RegExp * @throws ParserException if invalid source or flags */ public static RegExp create(final String pattern, final String flags) { diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java --- a/src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java Tue Mar 26 12:08:00 2013 -0700 @@ -80,11 +80,11 @@ /** * Get the group with the given index or the empty string if group index is not valid. - * @param index the group index + * @param groupIndex the group index * @return the group or "" */ - public Object getGroup(int index) { - return index >= 0 && index < groups.length ? groups[index] : ""; + public Object getGroup(final int groupIndex) { + return groupIndex >= 0 && groupIndex < groups.length ? groups[groupIndex] : ""; } /** diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java --- a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Tue Mar 26 12:08:00 2013 -0700 @@ -182,8 +182,6 @@ * @return Committed token */ private boolean commit(final int n) { - final int startIn = position; - switch (n) { case 1: sb.append(ch0); diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java Tue Mar 26 12:08:00 2013 -0700 @@ -1459,4 +1459,4 @@ private int finish() { return bestLen; } -} \ No newline at end of file +} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java --- a/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java Tue Mar 26 12:08:00 2013 -0700 @@ -154,4 +154,4 @@ {0x59, 0x79}, {0x5a, 0x7a} }; -} \ No newline at end of file +} diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/resources/Messages.properties --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties Tue Mar 26 12:08:00 2013 -0700 @@ -42,6 +42,8 @@ parser.error.expected.comma=Expected comma but found {0} parser.error.expected=Expected {0} but found {1} parser.error.invalid.return=Invalid return statement +parser.error.no.func.decl.here=Function declarations can only occur at program or function body level. You should use a function expression here instead. +parser.error.no.func.decl.here.warn=Function declarations should only occur at program or function body level. Function declaration in nested block was converted to a function expression. parser.error.property.redefinition=Property "{0}" already defined parser.error.unexpected.token=Unexpected token: {0} parser.error.many.vars.in.for.in.loop=Only one variable allowed in for..in loop @@ -57,7 +59,7 @@ parser.error.strict.cant.delete.ident=cannot delete identifier "{0}" in strict mode parser.error.strict.param.redefinition=strict mode function cannot have duplicate parameter name "{0}" parser.error.strict.no.octal=cannot use octal value in strict mode -parser.error.strict.no.func.here=In strict mode, functions can only be declared at top-level or immediately within a function +parser.error.strict.no.func.decl.here=In strict mode, function declarations can only occur at program or function body level. You should use a function expression here instead. type.error.strict.getter.setter.poison=In strict mode, "caller", "callee", and "arguments" properties can not be accessed on functions or the arguments object # not the expected type in a given context diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/resources/Options.properties --- a/src/jdk/nashorn/internal/runtime/resources/Options.properties Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties Tue Mar 26 12:08:00 2013 -0700 @@ -165,6 +165,12 @@ desc="Generate local variable table in .class files." \ } +nashorn.option.lazy.compilation = { \ + name="--lazy-compilation", \ + is_undocumented=true, \ + desc="EXPERIMENTAL: Use lazy code generation strategies - do not compile the entire script at once." \ +} + nashorn.option.loader.per.compile = { \ name="--loader-per-compile", \ is_undocumented=true, \ diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js --- a/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Tue Mar 26 12:08:00 2013 -0700 @@ -1,21 +1,21 @@ /* * 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. @@ -34,7 +34,7 @@ if (arguments.length < 2) { throw new TypeError("JavaAdapter requires atleast two arguments"); } - + var types = Array.prototype.slice.call(arguments, 0, arguments.length - 1); var NewType = Java.extend.apply(Java, types); return new NewType(arguments[arguments.length - 1]); @@ -56,10 +56,10 @@ return type; } catch (e) {} } - + return oldNoSuchProperty? oldNoSuchProperty(name) : undefined; } - + var prefix = "[JavaPackage "; return function() { for (var i in arguments) { @@ -343,7 +343,9 @@ configurable: true, enumerable: false, writable: true, value: function(clazz) { if (Java.isType(clazz)) { - this[clazz.class.getSimpleName()] = clazz; + var className = Java.typeName(clazz); + var simpleName = className.substring(className.lastIndexOf('.') + 1); + this[simpleName] = clazz; } else { throw new TypeError(clazz + " is not a Java class"); } diff -r 053d7c55dc82 -r db8a33cb22b8 src/jdk/nashorn/internal/runtime/resources/parser.js --- a/src/jdk/nashorn/internal/runtime/resources/parser.js Thu Mar 21 10:43:41 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/resources/parser.js Tue Mar 26 12:08:00 2013 -0700 @@ -1,21 +1,21 @@ /* * 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. @@ -47,7 +47,7 @@ code = arguments[0]; } - var jsonStr = Packages.jdk.nashorn.internal.runtime.ScriptRuntime.parse(code, name, location); + var jsonStr = Packages.jdk.nashorn.api.scripting.ScriptUtils.parse(code, name, location); return JSON.parse(jsonStr, function (prop, value) { if (typeof(value) == 'string' && prop == "value") { diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/JDK-8006755.js --- a/test/script/basic/JDK-8006755.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/JDK-8006755.js Tue Mar 26 12:08:00 2013 -0700 @@ -31,7 +31,7 @@ var scope = { x: "hello" }; with (scope) { - function main() { + var main = function() { if (x != "hello") { fail("x != 'hello'"); } diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/JDK-8008448.js --- a/test/script/basic/JDK-8008448.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/JDK-8008448.js Tue Mar 26 12:08:00 2013 -0700 @@ -32,7 +32,7 @@ var File = Java.type("java.io.File"); var FilenameFilter = Java.type("java.io.FilenameFilter"); -var Source = Java.type("jdk.nashorn.internal.runtime.Source") +var SourceHelper = Java.type("jdk.nashorn.test.models.SourceHelper") // Filter out non .js files var files = new File(__DIR__).listFiles(new FilenameFilter() { @@ -44,5 +44,5 @@ // parse each file to make sure it does not result in exception for each (var f in files) { - parse(new Source(f.toString(), f).getString()); + parse(SourceHelper.readFully(f)); } diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/JDK-8009868.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8009868.js Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,35 @@ +/* + * 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-8009868: For loop with "true" as condition results in AssertionError in codegen + * + * @test + * @run + */ + +// This used to crash with AssertionError in codegen +for(; true;) { + break; +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/JDK-8010199.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8010199.js Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,51 @@ +/* + * 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-8010199: javax.script.Invocable implementation for nashorn does not return null when matching functions are missing + * + * @test + * @run + */ + +var m = new javax.script.ScriptEngineManager(); +var e = m.getEngineByName("nashorn"); + +var iface = e.getInterface(java.lang.Runnable.class); + +if (iface != null) { + fail("Expected interface object to be null"); +} + +e.eval("var runcalled = false; function run() { runcalled = true }"); + +iface = e.getInterface(java.lang.Runnable.class); +if (iface == null) { + fail("Expected interface object to be non-null"); +} + +iface.run(); + +if (e.get("runcalled") != true) { + fail("runcalled is not true"); +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/JDK-8010709.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8010709.js Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,46 @@ +/* + * 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-8010709 org on the top level doesn't resolve + * + * @test + * @run + */ + +function check(pkgName) { + if (typeof this[pkgName] != 'object') { + fail(pkgName + " not defined"); + } + + if (String(this[pkgName]) != '[JavaPackage ' + pkgName + ']') { + fail(pkgName + " is not a JavaPackage"); + } +} + +check("com"); +check("edu"); +check("java"); +check("javafx"); +check("javax"); +check("org"); diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/JDK-8010720.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8010720.js Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,49 @@ +/* + * 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-8010720: Linkage problem with java.lang.String.length() + * + * @test + * @run + */ + +var s = new java.lang.String("nashorn"); + +if (s.length() != 7) { + fail("s.length() does not return expected value"); +} + +if (s.length != 7) { + fail("s.length does not return expected value"); +} + + +if ('hello'.length() != 5) { + fail("'hello'.length() does not return expected value"); +} + +if ('hello'.length != 5) { + fail("'hello'.length does not return expected value"); +} + diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/JDK-8017010.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8017010.js Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,68 @@ +/* + * 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-8010710 - slot/scope problem with temporary expressions + * as array index in self modifying assigns + * + * @test + * @run + */ +function zero() { + return 0; +} + +//try complex self modifying assignment and force slots to temporary value index operators +var a = [1, 2, 3, 4, 5]; +var b = [a, a]; +print(b[zero() + 1][2 + a[0]] += 10); + +//repro for NASHORN-258 that never made it +function AddRoundKey() { + var r=0; + state[r][1] &= 17; +} + +var srcFiles = []; +for(i=0;i<100;i++) { + srcFiles.push('dummy'); +} +var added = ''; + +//this broke the javafx build system. verify it works +function bouncingBall() { + for (j=0; j<100; j++) { + added += srcFiles[j]; + } +} +bouncingBall(); +print(added); + +//this is how they should have done it for speed, that works always, verify this too +function bouncingBall2() { + for (var k=0; k<100; k++) { + added += srcFiles[k]; + } +} +bouncingBall2(); +print(added); diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/JDK-8017010.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8017010.js.EXPECTED Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,3 @@ +14 +dummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummy +dummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummy diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/NASHORN-258.js --- a/test/script/basic/NASHORN-258.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/NASHORN-258.js Tue Mar 26 12:08:00 2013 -0700 @@ -29,6 +29,16 @@ */ function test3(a) { + for (i = 0; i < a.length ; i++) { + for (j = 0; j < a[i].length ; j++) { + for (k = 0; k < a[i][j].length ; k++) { + a[i][j][k] *= 8; + } + } + } +} + +function test3local(a) { for (var i = 0; i < a.length ; i++) { for (var j = 0; j < a[i].length ; j++) { for (var k = 0; k < a[i][j].length ; k++) { @@ -45,6 +55,8 @@ test3(array); print(array); +test3local(array); +print(array); function outer() { diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/NASHORN-258.js.EXPECTED --- a/test/script/basic/NASHORN-258.js.EXPECTED Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/NASHORN-258.js.EXPECTED Tue Mar 26 12:08:00 2013 -0700 @@ -1,2 +1,3 @@ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64 1,1,8,1,1,8,1,1,8,1,1,8,1,1,8,1,1,8,1,1,8,1,1,8,1,1,8 diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/NASHORN-401.js --- a/test/script/basic/NASHORN-401.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/NASHORN-401.js Tue Mar 26 12:08:00 2013 -0700 @@ -28,7 +28,7 @@ * @run */ -var t = new Packages.jdk.nashorn.internal.runtime.Nashorn401TestSubject(); +var t = new Packages.jdk.nashorn.test.models.Nashorn401TestSubject(); print(t.method2(10)); print(t.method2(10.2)); diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/NASHORN-837.js --- a/test/script/basic/NASHORN-837.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/NASHORN-837.js Tue Mar 26 12:08:00 2013 -0700 @@ -28,23 +28,13 @@ * @run */ -var failed = false; - try { - try { - throw new TypeError('error'); - } catch (iox) { - function f() { - print(iox.message); - } + throw new TypeError('error'); +} catch (iox) { + var f = function() { + if(iox.message != 'error') { + print("Failure! iox did not throw correct exception"); + } } - f(); -} catch (e) { - failed = (e instanceof ReferenceError); - //iox not defined should be thrown } - -if (!failed) { - print("Failure! iox did not throw correct exception"); -} - +f(); diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/compile-octane.js.EXPECTED --- a/test/script/basic/compile-octane.js.EXPECTED Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/compile-octane.js.EXPECTED Tue Mar 26 12:08:00 2013 -0700 @@ -16,6 +16,9 @@ Compiling... gbemu.js Compiled OK: gbemu.js +Compiling... mandreel.js +Compiled OK: mandreel.js + Compiling... navier-stokes.js Compiled OK: navier-stokes.js diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/consstring.js --- a/test/script/basic/consstring.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/consstring.js Tue Mar 26 12:08:00 2013 -0700 @@ -37,4 +37,4 @@ list.add((str + "3").toString()); // toString() called on primitive string list.add(new String(str + "4").toString()); // toString() called on String object -Packages.jdk.nashorn.internal.test.models.StringArgs.checkString(list); +Packages.jdk.nashorn.test.models.StringArgs.checkString(list); diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/fileline.js --- a/test/script/basic/fileline.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/fileline.js Tue Mar 26 12:08:00 2013 -0700 @@ -41,8 +41,8 @@ load(__DIR__ + "loadedfile.js"); // Add check for base part of a URL. We can't test __DIR__ inside -// a script that is downloaded from a URL. check for Source.baseURL +// a script that is downloaded from a URL. check for SourceHelper.baseURL // which is exposed as __DIR__ for URL case. var url = new java.net.URL("http://www.acme.com:8080/foo/bar.js"); -print(Packages.jdk.nashorn.internal.runtime.Source.baseURL(url)); +print(Packages.jdk.nashorn.test.models.SourceHelper.baseURL(url)); diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/javainnerclasses.js --- a/test/script/basic/javainnerclasses.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/javainnerclasses.js Tue Mar 26 12:08:00 2013 -0700 @@ -29,25 +29,25 @@ */ // Do it with Java.type() -var outer = new (Java.type("jdk.nashorn.internal.test.models.OuterClass"))("apple") +var outer = new (Java.type("jdk.nashorn.test.models.OuterClass"))("apple") print(outer) -var innerStatic = new (Java.type("jdk.nashorn.internal.test.models.OuterClass$InnerStaticClass"))("orange") +var innerStatic = new (Java.type("jdk.nashorn.test.models.OuterClass$InnerStaticClass"))("orange") print(innerStatic) -var innerNonStatic = new (Java.type("jdk.nashorn.internal.test.models.OuterClass$InnerNonStaticClass"))(outer, "pear") +var innerNonStatic = new (Java.type("jdk.nashorn.test.models.OuterClass$InnerNonStaticClass"))(outer, "pear") print(innerNonStatic) // Now do it with Packages and explicit $ names -var outer = new Packages.jdk.nashorn.internal.test.models.OuterClass("red") +var outer = new Packages.jdk.nashorn.test.models.OuterClass("red") print(outer) -var innerStatic = new Packages.jdk.nashorn.internal.test.models.OuterClass$InnerStaticClass("green") +var innerStatic = new Packages.jdk.nashorn.test.models.OuterClass$InnerStaticClass("green") print(innerStatic) -var innerNonStatic = new Packages.jdk.nashorn.internal.test.models.OuterClass$InnerNonStaticClass(outer, "blue") +var innerNonStatic = new Packages.jdk.nashorn.test.models.OuterClass$InnerNonStaticClass(outer, "blue") print(innerNonStatic) // Now do it with Packages and nested properties -var outer = new Packages.jdk.nashorn.internal.test.models.OuterClass("sweet") +var outer = new Packages.jdk.nashorn.test.models.OuterClass("sweet") print(outer) -var innerStatic = new Packages.jdk.nashorn.internal.test.models.OuterClass.InnerStaticClass("sour") +var innerStatic = new Packages.jdk.nashorn.test.models.OuterClass.InnerStaticClass("sour") print(innerStatic) -var innerNonStatic = new Packages.jdk.nashorn.internal.test.models.OuterClass.InnerNonStaticClass(outer, "bitter") +var innerNonStatic = new Packages.jdk.nashorn.test.models.OuterClass.InnerNonStaticClass(outer, "bitter") print(innerNonStatic) diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/list.js --- a/test/script/basic/list.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/list.js Tue Mar 26 12:08:00 2013 -0700 @@ -28,7 +28,7 @@ * @run */ var l = new java.util.ArrayList(); -print("l.class.name=" + l.class.name) // Has "class" property like any POJO +print("l.class.name=" + Java.typeName(l.class)) // Has "class" property like any POJO l.add("foo") l.add("bar") diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/map.js --- a/test/script/basic/map.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/map.js Tue Mar 26 12:08:00 2013 -0700 @@ -28,7 +28,7 @@ * @run */ var m = new (Java.type("java.util.LinkedHashMap")); -print("m.class.name=" + m.class.name) // Has "class" property like any POJO +print("m.class.name=" + Java.typeName(m.class)) // Has "class" property like any POJO var empty_key = "empty" diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/run-octane.js --- a/test/script/basic/run-octane.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/run-octane.js Tue Mar 26 12:08:00 2013 -0700 @@ -31,7 +31,8 @@ "crypto.js", "deltablue.js", "earley-boyer.js", - "gbemu.js", + "gbemu.js", + "mandreel.js", "navier-stokes.js", "pdfjs.js", "raytrace.js", @@ -49,6 +50,12 @@ { name: "gbemu.js" }, ]; + +//TODO mandreel can be compiled as a test, but not run multiple times unless modified to not have global state +var compileOnly = { + "mandreel.js" : true +}; + var dir = (typeof(__DIR__) == 'undefined') ? "test/script/basic/" : __DIR__; // TODO: why is this path hard coded when it's defined in project properties? @@ -63,6 +70,10 @@ return str.indexOf(suffix, str.length - suffix.length) !== -1; } +function should_compile_only(name) { + return (typeof compile_only !== 'undefined') || compileOnly[name] === true; +} + function run_one_benchmark(arg, iters) { var file_name; @@ -77,14 +88,18 @@ } file_name = file[file.length - 1]; - if (typeof compile_only !== 'undefined') { + var compile_and_return = should_compile_only(file_name); + if (compile_and_return) { + if (typeof compile_only === 'undefined') { //for a run, skip compile onlies, don't even compile them + return; + } print("Compiling... " + file_name); } load(path + 'base.js'); load(arg); - if (typeof compile_only !== 'undefined') { + if (compile_and_return) { print("Compiled OK: " + file_name); print(""); return; @@ -164,7 +179,7 @@ function run_suite(tests, iters) { for (var idx = 0; idx < tests.length; idx++) { - run_one_benchmark(tests[idx], iters, false); + run_one_benchmark(tests[idx], iters); } } diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/runsunspider-eager.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/runsunspider-eager.js Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * runsunspider : runs the sunspider tests and checks for compliance + * + * @test + * @option -timezone=PST + * @runif external.sunspider + */ + +load(__DIR__ + "runsunspider.js"); + diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/runsunspider-eager.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/runsunspider-eager.js.EXPECTED Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,1 @@ +Sunspider finished! diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/runsunspider-lazy.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/runsunspider-lazy.js Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/** + * runsunspider : runs the sunspider tests and checks for compliance + * + * @test + * @option -timezone=PST + * @option --lazy-compilation + * @runif external.sunspider + */ + +load(__DIR__ + "runsunspider.js"); + diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/runsunspider-lazy.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/runsunspider-lazy.js.EXPECTED Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,1 @@ +Sunspider finished! diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/runsunspider.js --- a/test/script/basic/runsunspider.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/runsunspider.js Tue Mar 26 12:08:00 2013 -0700 @@ -24,39 +24,11 @@ /** * runsunspider : runs the sunspider tests and checks for compliance * - * @test - * @option -timezone=PST - * @runif external.sunspider - */ - -/* - * Copyright (c) 2010-2011, 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. + * @subtest */ /** * This is not a test, but a test "framework" for running sunspider tests. - * */ function assertEq(a, b) { diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/runsunspider.js.EXPECTED --- a/test/script/basic/runsunspider.js.EXPECTED Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -Sunspider finished! diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/basic/stdin.js --- a/test/script/basic/stdin.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/basic/stdin.js Tue Mar 26 12:08:00 2013 -0700 @@ -28,8 +28,8 @@ * @run */ -print(java.lang.System.in.class.name); +print(Java.typeName(java.lang.System.in.class)); var prop = "in"; -print(java.lang.System[prop].class.name); -print(java.lang.System["in"].class.name); +print(Java.typeName(java.lang.System[prop].class)); +print(Java.typeName(java.lang.System["in"].class)); diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/currently-failing/JDK-8006529.js --- a/test/script/currently-failing/JDK-8006529.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/currently-failing/JDK-8006529.js Tue Mar 26 12:08:00 2013 -0700 @@ -39,12 +39,13 @@ * and FunctionNode because of package-access check and so reflective calls. */ -var Parser = Java.type("jdk.nashorn.internal.parser.Parser") -var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") -var Context = Java.type("jdk.nashorn.internal.runtime.Context") +var Parser = Java.type("jdk.nashorn.internal.parser.Parser") +var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") +var Context = Java.type("jdk.nashorn.internal.runtime.Context") var ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment") -var Source = Java.type("jdk.nashorn.internal.runtime.Source") -var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode") +var Source = Java.type("jdk.nashorn.internal.runtime.Source") +var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode") +var ThrowErrorManager = Java.type("jdk.nashorn.internal.runtime.Context$ThrowErrorManager"); // Compiler class methods and fields var parseMethod = Parser.class.getMethod("parse"); @@ -90,7 +91,7 @@ // representing it. function compile(source) { var source = new Source("", source); - var parser = new Parser(Context.getContext().getEnv(), source, null); + var parser = new Parser(Context.getContext().getEnv(), source, new ThrowErrorManager()); var func = parseMethod.invoke(parser); var compiler = new Compiler(Context.getContext().getEnv(), func); diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/currently-failing/clone_ir.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/currently-failing/clone_ir.js Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/** + * clone_ir : Check that functionNode.clone copies all nodes and that they + * are not the same references + * + * @test + * @run + */ + +var js1 = "var tuple = { func : function f(x) { if (x) { print('true'); { print('block_under-true'); } } else { print('false'); } } }"; + +var Parser = Java.type("jdk.nashorn.internal.parser.Parser"); +var ASTWriter = Java.type("jdk.nashorn.internal.ir.debug.ASTWriter"); +var Context = Java.type("jdk.nashorn.internal.runtime.Context"); +var ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment"); +var Source = Java.type("jdk.nashorn.internal.runtime.Source"); +var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode"); +var ThrowErrorManager = Java.type("jdk.nashorn.internal.runtime.Context$ThrowErrorManager"); +var System = Java.type("java.lang.System"); + +var toArrayMethod = ASTWriter.class.getMethod("toArray"); +var parseMethod = Parser.class.getMethod("parse"); + +function toString(obj) { + var output = "{ "; + for (property in obj) { + output += property + ': ' + obj[property]+'; '; + } + return output + '}' +} + +function flatten(func) { + var writer = new ASTWriter(func); + var funcList = toArrayMethod.invoke(writer); + + var res = []; + for each (x in funcList) { + res.push({ name: x.getClass().getName(), id: System.identityHashCode(x) }); + } + return res; +} + +function check(contents) { + return check_src(new Source("", contents)); +} + +function check_src(src) { + var parser = new Parser(Context.getContext().getEnv(), src, new ThrowErrorManager()); + + var func = parseMethod.invoke(parser); + print(func); + var func2 = func.clone(); + + var f1 = flatten(func); + var f2 = flatten(func2); + + print(f1.map(toString)); + print(f2.map(toString)); + + if (f1.length != f2.length) { + print("length difference between original and clone " + f1.length + " != " + f2.length); + return false; + } + + for (var i = 0; i < f1.length; i++) { + if (f1[i].name !== f2[i].name) { + print("name conflict at " + i + " " + f1[i].name + " != " + f2[i].name); + return false; + } else if (f1[i].id === f2[i].id) { + print("id problem at " + i + " " + toString(f1[i]) + " was not deep copied to " + toString(f2[i]) + " became " + f1[i].id + " != " + f2[i].id); + return false; + } + } + + return true; +} + +print(check(js1)); diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/sandbox/javaextend.js --- a/test/script/sandbox/javaextend.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/sandbox/javaextend.js Tue Mar 26 12:08:00 2013 -0700 @@ -27,7 +27,7 @@ */ function model(n) { - return Java.type("jdk.nashorn.internal.test.models." + n) + return Java.type("jdk.nashorn.test.models." + n) } // Can't extend a final class diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/sandbox/javaextend.js.EXPECTED --- a/test/script/sandbox/javaextend.js.EXPECTED Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/sandbox/javaextend.js.EXPECTED Tue Mar 26 12:08:00 2013 -0700 @@ -1,6 +1,6 @@ -TypeError: Can not extend final class jdk.nashorn.internal.test.models.FinalClass. -TypeError: Can not extend class jdk.nashorn.internal.test.models.NoAccessibleConstructorClass as it has no public or protected constructors. -TypeError: Can not extend/implement non-public class/interface jdk.nashorn.internal.test.models.NonPublicClass. +TypeError: Can not extend final class jdk.nashorn.test.models.FinalClass. +TypeError: Can not extend class jdk.nashorn.test.models.NoAccessibleConstructorClass as it has no public or protected constructors. +TypeError: Can not extend/implement non-public class/interface jdk.nashorn.test.models.NonPublicClass. TypeError: Can not extend multiple classes java.lang.Number and java.lang.Thread. At most one of the specified types can be a class, the rest must all be interfaces. abcdabcd run-object diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/sandbox/reflection.js --- a/test/script/sandbox/reflection.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/sandbox/reflection.js Tue Mar 26 12:08:00 2013 -0700 @@ -30,9 +30,7 @@ */ function check(e) { - if (e instanceof java.lang.SecurityException) { - print(e); - } else { + if (! (e instanceof java.lang.SecurityException)) { fail("expected SecurityException, got " + e); } } diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/sandbox/reflection.js.EXPECTED --- a/test/script/sandbox/reflection.js.EXPECTED Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers") diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/sandbox/unsafe.js --- a/test/script/sandbox/unsafe.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/sandbox/unsafe.js Tue Mar 26 12:08:00 2013 -0700 @@ -30,9 +30,7 @@ */ function check(e) { - if (e instanceof java.lang.SecurityException) { - print(e); - } else { + if (! (e instanceof java.lang.SecurityException)) { fail("expected SecurityException, got " + e); } } diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/sandbox/unsafe.js.EXPECTED --- a/test/script/sandbox/unsafe.js.EXPECTED Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun.misc") -java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun.misc") -java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun") -java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getClassLoader") diff -r 053d7c55dc82 -r db8a33cb22b8 test/script/trusted/urlreader.js --- a/test/script/trusted/urlreader.js Thu Mar 21 10:43:41 2013 -0700 +++ b/test/script/trusted/urlreader.js Tue Mar 26 12:08:00 2013 -0700 @@ -9,7 +9,7 @@ var URL = Java.type("java.net.URL"); var File = Java.type("java.io.File"); var JString = Java.type("java.lang.String"); -var Source = Java.type("jdk.nashorn.internal.runtime.Source"); +var SourceHelper = Java.type("jdk.nashorn.test.models.SourceHelper"); var url = new File(__FILE__).toURI().toURL(); var reader = new URLReader(url); @@ -19,9 +19,9 @@ // check URL read // read URL content by directly reading from URL -var str = new Source(url.toString(), url).getString(); +var str = SourceHelper.readFully(url); // read URL content via URLReader -var content = new JString(Source.readFully(reader)); +var content = new JString(SourceHelper.readFully(reader)); // assert that the content is same Assert.assertEquals(str, content); diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java --- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Thu Mar 21 10:43:41 2013 -0700 +++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Tue Mar 26 12:08:00 2013 -0700 @@ -47,7 +47,6 @@ import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.script.SimpleScriptContext; -import jdk.nashorn.internal.runtime.Version; import netscape.javascript.JSObject; import org.testng.Assert; import org.testng.annotations.Test; @@ -129,7 +128,6 @@ assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript"); assertEquals(fac.getLanguageVersion(), "ECMA - 262 Edition 5.1"); assertEquals(fac.getEngineName(), "Oracle Nashorn"); - assertEquals(fac.getEngineVersion(), Version.version()); assertEquals(fac.getOutputStatement("context"), "print(context)"); assertEquals(fac.getProgram("print('hello')", "print('world')"), "print('hello');print('world');"); assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript"); @@ -285,6 +283,68 @@ } } + public interface Foo { + public void bar(); + } + + public interface Foo2 extends Foo { + public void bar2(); + } + + @Test + public void getInterfaceMissingTest() { + final ScriptEngineManager manager = new ScriptEngineManager(); + final ScriptEngine engine = manager.getEngineByName("nashorn"); + + // don't define any function. + try { + engine.eval(""); + } catch (final Exception exp) { + exp.printStackTrace(); + fail(exp.getMessage()); + } + + Runnable runnable = ((Invocable)engine).getInterface(Runnable.class); + if (runnable != null) { + fail("runnable is not null!"); + } + + // now define "run" + try { + engine.eval("function run() { print('this is run function'); }"); + } catch (final Exception exp) { + exp.printStackTrace(); + fail(exp.getMessage()); + } + runnable = ((Invocable)engine).getInterface(Runnable.class); + // should not return null now! + runnable.run(); + + // define only one method of "Foo2" + try { + engine.eval("function bar() { print('bar function'); }"); + } catch (final Exception exp) { + exp.printStackTrace(); + fail(exp.getMessage()); + } + + Foo2 foo2 = ((Invocable)engine).getInterface(Foo2.class); + if (foo2 != null) { + throw new RuntimeException("foo2 is not null!"); + } + + // now define other method of "Foo2" + try { + engine.eval("function bar2() { print('bar2 function'); }"); + } catch (final Exception exp) { + exp.printStackTrace(); + fail(exp.getMessage()); + } + foo2 = ((Invocable)engine).getInterface(Foo2.class); + foo2.bar(); + foo2.bar2(); + } + @Test public void accessGlobalTest() { final ScriptEngineManager m = new ScriptEngineManager(); @@ -313,27 +373,6 @@ } } - public static void alert(final Object msg) { - System.out.println(msg); - } - - @Test - public void exposeMethodTest() { - final ScriptEngineManager m = new ScriptEngineManager(); - final ScriptEngine e = m.getEngineByName("nashorn"); - - try { - final Method alert = ScriptEngineTest.class.getMethod("alert", Object.class); - // expose a Method object as global var. - e.put("alert", alert); - // call the global var. - e.eval("alert.invoke(null, 'alert! alert!!')"); - } catch (final NoSuchMethodException | SecurityException | ScriptException exp) { - exp.printStackTrace(); - fail(exp.getMessage()); - } - } - @Test public void putGlobalFunctionTest() { final ScriptEngineManager m = new ScriptEngineManager(); @@ -593,13 +632,6 @@ } @Test - public void versionTest() { - final ScriptEngineManager m = new ScriptEngineManager(); - final ScriptEngine e = m.getEngineByName("nashorn"); - assertEquals(e.getFactory().getEngineVersion(), Version.version()); - } - - @Test public void noEnumerablePropertiesTest() { final ScriptEngineManager m = new ScriptEngineManager(); final ScriptEngine e = m.getEngineByName("nashorn"); @@ -874,26 +906,4 @@ fail(se.getMessage()); } } - - @Test - public void factoryOptionsTest() { - final ScriptEngineManager sm = new ScriptEngineManager(); - for (ScriptEngineFactory fac : sm.getEngineFactories()) { - if (fac instanceof NashornScriptEngineFactory) { - final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; - // specify --no-syntax-extensions flag - final String[] options = new String[] { "--no-syntax-extensions" }; - final ScriptEngine e = nfac.getScriptEngine(options); - try { - // try nashorn specific extension - e.eval("var f = funtion(x) 2*x;"); - fail("should have thrown exception!"); - } catch (final ScriptException se) { - } - return; - } - } - - fail("Cannot find nashorn factory!"); - } } diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/codegen/CompilerTest.java --- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Thu Mar 21 10:43:41 2013 -0700 +++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Tue Mar 26 12:08:00 2013 -0700 @@ -44,6 +44,7 @@ private static final boolean VERBOSE = Boolean.valueOf(System.getProperty("compilertest.verbose")); private static final boolean TEST262 = Boolean.valueOf(System.getProperty("compilertest.test262")); private static final String TEST_BASIC_DIR = System.getProperty("test.basic.dir"); + private static final String TEST_NODE_DIR = System.getProperty("test.node.dir"); private static final String TEST262_SUITE_DIR = System.getProperty("test262.suite.dir"); interface TestFilter { @@ -81,21 +82,22 @@ @Test public void compileAllTests() { if (TEST262) { - compileTestSet(TEST262_SUITE_DIR, new TestFilter() { + compileTestSet(new File(TEST262_SUITE_DIR), new TestFilter() { @Override public boolean exclude(final File file, final String content) { return content.indexOf("@negative") != -1; } }); } - compileTestSet(TEST_BASIC_DIR, null); + compileTestSet(new File(TEST_BASIC_DIR), null); + compileTestSet(new File(TEST_NODE_DIR, "node"), null); + compileTestSet(new File(TEST_NODE_DIR, "src"), null); } - private void compileTestSet(final String testSet, final TestFilter filter) { + private void compileTestSet(final File testSetDir, final TestFilter filter) { passed = 0; failed = 0; skipped = 0; - final File testSetDir = new File(testSet); if (! testSetDir.isDirectory()) { log("WARNING: " + testSetDir + " not found or not a directory"); return; @@ -103,7 +105,7 @@ log(testSetDir.getAbsolutePath()); compileJSDirectory(testSetDir, filter); - log(testSet + " compile done!"); + log(testSetDir + " compile done!"); log("compile ok: " + passed); log("compile failed: " + failed); log("compile skipped: " + skipped); diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/runtime/Nashorn401TestSubject.java --- a/test/src/jdk/nashorn/internal/runtime/Nashorn401TestSubject.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.runtime; - -public class Nashorn401TestSubject { - public String method2(int arg) { - return "int method 2"; - } - - public String method2(double arg) { - return "double method 2"; - } - - public String method2(String arg) { - return "string method 2"; - } - - public String method3(double arg) { - return "double method 3: " + arg; - } - - public String method3(int arg) { - return "int method 3: " + arg; - } - - public String method4(Double arg) { - return "double method 4: " + arg; - } - - public String method4(int arg) { - return "int method 4: " + arg; - } - -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java --- a/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java Thu Mar 21 10:43:41 2013 -0700 +++ b/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java Tue Mar 26 12:08:00 2013 -0700 @@ -25,7 +25,7 @@ package jdk.nashorn.internal.runtime; - +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -40,6 +40,13 @@ * Tests for trusted client usage of nashorn script engine factory extension API */ public class TrustedScriptEngineTest { + @Test + public void versionTest() { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + assertEquals(e.getFactory().getEngineVersion(), Version.version()); + } + private static class MyClassLoader extends ClassLoader { // to check if script engine uses the specified class loader private final boolean[] reached = new boolean[1]; @@ -116,4 +123,26 @@ fail("Cannot find nashorn factory!"); } + + @Test + public void factoryOptionsTest() { + final ScriptEngineManager sm = new ScriptEngineManager(); + for (ScriptEngineFactory fac : sm.getEngineFactories()) { + if (fac instanceof NashornScriptEngineFactory) { + final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; + // specify --no-syntax-extensions flag + final String[] options = new String[] { "--no-syntax-extensions" }; + final ScriptEngine e = nfac.getScriptEngine(options); + try { + // try nashorn specific extension + e.eval("var f = funtion(x) 2*x;"); + fail("should have thrown exception!"); + } catch (final ScriptException se) { + } + return; + } + } + + fail("Cannot find nashorn factory!"); + } } diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/ConstructorWithArgument.java --- a/test/src/jdk/nashorn/internal/test/models/ConstructorWithArgument.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -public abstract class ConstructorWithArgument { - private final String token; - - protected ConstructorWithArgument(String token) { - this.token = token; - } - - public String getToken() { - return token; - } - - protected abstract void doSomething(); -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/DessertTopping.java --- a/test/src/jdk/nashorn/internal/test/models/DessertTopping.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -public interface DessertTopping { - public String pourOnDessert(); -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/DessertToppingFloorWaxDriver.java --- a/test/src/jdk/nashorn/internal/test/models/DessertToppingFloorWaxDriver.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -public class DessertToppingFloorWaxDriver { - public void decorateDessert(DessertTopping dt) { - dt.pourOnDessert(); - } - - public void waxFloor(FloorWax fw) { - fw.shineUpTheFloor(); - } -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/FinalClass.java --- a/test/src/jdk/nashorn/internal/test/models/FinalClass.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -public final class FinalClass { - //empty -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/FloorWax.java --- a/test/src/jdk/nashorn/internal/test/models/FloorWax.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -public interface FloorWax { - public String shineUpTheFloor(); -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/NoAccessibleConstructorClass.java --- a/test/src/jdk/nashorn/internal/test/models/NoAccessibleConstructorClass.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -public class NoAccessibleConstructorClass { - NoAccessibleConstructorClass() { } -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/NonPublicClass.java --- a/test/src/jdk/nashorn/internal/test/models/NonPublicClass.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -class NonPublicClass { - public NonPublicClass() { } -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/OuterClass.java --- a/test/src/jdk/nashorn/internal/test/models/OuterClass.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -public class OuterClass { - private final String value; - - public OuterClass(String value) { - this.value = value; - } - - public static class InnerStaticClass { - private final String value; - - public InnerStaticClass(String value) { - this.value = value; - } - - @Override - public String toString() { - return "InnerStaticClass[value=" + value + "]"; - } - } - - public class InnerNonStaticClass { - private final String value; - - public InnerNonStaticClass(String value) { - this.value = value; - } - - @Override - public String toString() { - return "InnerNonStaticClass[value=" + value + ", outer=" + OuterClass.this + "]"; - } - } - - @Override - public String toString() { - return "OuterClass[value=" + value + "]"; - } -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/OverloadedSam.java --- a/test/src/jdk/nashorn/internal/test/models/OverloadedSam.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -public interface OverloadedSam { - public void sam(String s); - public void sam(String s1, String s2); -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/OverrideObject.java --- a/test/src/jdk/nashorn/internal/test/models/OverrideObject.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -public class OverrideObject { - @Override - public int hashCode() { - return 5; - } - - @Override - public String toString() { - return "override-object"; - } - - @Override - public boolean equals(Object o) { - // TODO: add a FindBugs annotation to ignore EQ_ALWAYS_FALSE here. This is just a test. - return false; - } -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/StringArgs.java --- a/test/src/jdk/nashorn/internal/test/models/StringArgs.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -import java.util.List; - -public class StringArgs { - - public static void checkString(List list) { - for (Object s : list) { - if (!(s instanceof String)) { - throw new AssertionError("Not a String: " + s); - } - } - } -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/internal/test/models/Toothpaste.java --- a/test/src/jdk/nashorn/internal/test/models/Toothpaste.java Thu Mar 21 10:43:41 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * 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. 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. - */ - -package jdk.nashorn.internal.test.models; - -public abstract class Toothpaste { - public void applyToBrush() { - applyToBrushImpl(); - } - - protected abstract void applyToBrushImpl(); -} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/ConstructorWithArgument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/ConstructorWithArgument.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,40 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public abstract class ConstructorWithArgument { + private final String token; + + protected ConstructorWithArgument(String token) { + this.token = token; + } + + public String getToken() { + return token; + } + + protected abstract void doSomething(); +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/DessertTopping.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/DessertTopping.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,30 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public interface DessertTopping { + public String pourOnDessert(); +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/DessertToppingFloorWaxDriver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/DessertToppingFloorWaxDriver.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,36 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public class DessertToppingFloorWaxDriver { + public void decorateDessert(DessertTopping dt) { + dt.pourOnDessert(); + } + + public void waxFloor(FloorWax fw) { + fw.shineUpTheFloor(); + } +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/FinalClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/FinalClass.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,30 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public final class FinalClass { + //empty +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/FloorWax.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/FloorWax.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,30 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public interface FloorWax { + public String shineUpTheFloor(); +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/Nashorn401TestSubject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/Nashorn401TestSubject.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,57 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public class Nashorn401TestSubject { + public String method2(int arg) { + return "int method 2"; + } + + public String method2(double arg) { + return "double method 2"; + } + + public String method2(String arg) { + return "string method 2"; + } + + public String method3(double arg) { + return "double method 3: " + arg; + } + + public String method3(int arg) { + return "int method 3: " + arg; + } + + public String method4(Double arg) { + return "double method 4: " + arg; + } + + public String method4(int arg) { + return "int method 4: " + arg; + } + +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/NoAccessibleConstructorClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/NoAccessibleConstructorClass.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,30 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public class NoAccessibleConstructorClass { + NoAccessibleConstructorClass() { } +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/NonPublicClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/NonPublicClass.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,30 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +class NonPublicClass { + public NonPublicClass() { } +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/OuterClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/OuterClass.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,65 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public class OuterClass { + private final String value; + + public OuterClass(String value) { + this.value = value; + } + + public static class InnerStaticClass { + private final String value; + + public InnerStaticClass(String value) { + this.value = value; + } + + @Override + public String toString() { + return "InnerStaticClass[value=" + value + "]"; + } + } + + public class InnerNonStaticClass { + private final String value; + + public InnerNonStaticClass(String value) { + this.value = value; + } + + @Override + public String toString() { + return "InnerNonStaticClass[value=" + value + ", outer=" + OuterClass.this + "]"; + } + } + + @Override + public String toString() { + return "OuterClass[value=" + value + "]"; + } +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/OverloadedSam.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/OverloadedSam.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,31 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public interface OverloadedSam { + public void sam(String s); + public void sam(String s1, String s2); +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/OverrideObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/OverrideObject.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,44 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public class OverrideObject { + @Override + public int hashCode() { + return 5; + } + + @Override + public String toString() { + return "override-object"; + } + + @Override + public boolean equals(Object o) { + // TODO: add a FindBugs annotation to ignore EQ_ALWAYS_FALSE here. This is just a test. + return false; + } +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/SourceHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/SourceHelper.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,55 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.net.URL; +import jdk.nashorn.internal.runtime.Source; + +/** + * Helper class to facilitate script access of nashorn Source class. + */ +public final class SourceHelper { + private SourceHelper() {} + + public static String baseURL(final URL url) { + return Source.baseURL(url); + } + + public static String readFully(final File file) throws IOException { + return new String(Source.readFully(file)); + } + + public static String readFully(final URL url) throws IOException { + return new Source(url.toString(), url).getString(); + } + + public static String readFully(final Reader reader) throws IOException { + return new String(Source.readFully(reader)); + } +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/StringArgs.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/StringArgs.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,39 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +import java.util.List; + +public class StringArgs { + + public static void checkString(List list) { + for (Object s : list) { + if (!(s instanceof String)) { + throw new AssertionError("Not a String: " + s); + } + } + } +} diff -r 053d7c55dc82 -r db8a33cb22b8 test/src/jdk/nashorn/test/models/Toothpaste.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/test/models/Toothpaste.java Tue Mar 26 12:08:00 2013 -0700 @@ -0,0 +1,34 @@ +/* + * 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. 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. + */ + +package jdk.nashorn.test.models; + +public abstract class Toothpaste { + public void applyToBrush() { + applyToBrushImpl(); + } + + protected abstract void applyToBrushImpl(); +}