提交 d822d2a8 编写于 作者: L lana

Merge

......@@ -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 $*
......@@ -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 $*
......@@ -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 $*
......@@ -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 $*
......@@ -13,6 +13,17 @@ properties described herein are subject to change without notice.
This documentation of the system property flags assume that the
default value of the flag is false, unless otherwise specified.
SYSTEM PROPERTY: -Dnashorn.args=<string>
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
......
......@@ -533,9 +533,8 @@ with (SwingGui) {
<hr>
<a name="jsarrays" id="jsarrays"></a>
<h3>Creating, Converting and Using Java Arrays</h3>
<p>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
<p>
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.</p>
......@@ -543,7 +542,8 @@ don't have to create Java arrays explicitly.</p>
// <a href="source/javaarray.js">javaarray.js</a>
// 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!";
......
......@@ -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!";
......
......@@ -124,7 +124,7 @@
<echo message="release=${nashorn.version}" file="${build.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties" append="true"/>
</target>
<target name="jar" depends="compile, run-nasgen" description="Creates nashorn.jar">
<target name="jar" depends="compile, run-nasgen, generate-cc-template" description="Creates nashorn.jar">
<jar jarfile="${dist.jar}" manifest="${meta.inf.dir}/MANIFEST.MF" index="true" filesetmanifest="merge">
<fileset dir="${build.classes.dir}"/>
<manifest>
......@@ -191,12 +191,12 @@
<!-- tests that check nashorn internals and internal API -->
<jar jarfile="${nashorn.internal.tests.jar}">
<fileset dir="${build.test.classes.dir}" excludes="**/api/*"/>
<fileset dir="${build.test.classes.dir}" excludes="**/api/**"/>
</jar>
<!-- tests that check nashorn script engine (jsr-223) API -->
<jar jarfile="${nashorn.api.tests.jar}">
<fileset dir="${build.test.classes.dir}" includes="**/api/*"/>
<fileset dir="${build.test.classes.dir}" includes="**/api/**"/>
</jar>
</target>
......
......@@ -36,7 +36,12 @@
<equals arg1="${jcov}" arg2="dynamic" trim="true"/>
</condition>
<condition property="cc.generate.template" value="true">
<equals arg1="${cc.dynamic.genereate.template}" arg2="true" trim="true"/>
</condition>
<mkdir dir="${cc.dir}"/>
<mkdir dir="${build.dir}/to_be_instrumented"/>
<!-- info -->
<echo message="jcov=${jcov}"/>
......@@ -51,25 +56,66 @@
<property name="run.test.cc.jvmargs" value=""/>
</target>
<target name="prepare-to-be-instrumented" depends="compile" description="Prepares to_be_instrumented dir">
<copy todir="${build.dir}/to_be_instrumented">
<fileset dir="${build.classes.dir}">
<include name="**/*.class"/>
<include name="**/*.clazz"/>
</fileset>
</copy>
<move todir="${build.dir}/to_be_instrumented/jdk/nashorn/internal/objects">
<fileset dir="${build.dir}/to_be_instrumented/jdk/nashorn/internal/objects">
<include name="**/*.clazz"/>
</fileset>
<mapper type="glob" from="*.clazz" to="*.class"/>
</move>
</target>
<target name="generate-cc-template" depends="prepare-to-be-instrumented" description="Generates code coverage template for dynamic CC" if="cc.generate.template">
<property name="cc.instrumented.path" location="${build.dir}/to_be_instrumented"/>
<java classname="com.sun.tdk.jcov.TmplGen">
<arg value="-verbose"/>
<arg line="-include ${cc.include}"/>
<arg line="-type all"/>
<arg line="-template ${cc.template}"/>
<arg value="${cc.instrumented.path}"/>
<classpath>
<pathelement location="${jcov.jar}"/>
</classpath>
</java>
<java classname="com.sun.tdk.jcov.RepGen">
<arg value="-verbose"/>
<arg line="-output ${cc.dir}/CC_template_report"/>
<arg value="${cc.template}"/>
<classpath>
<pathelement location="${jcov.jar}"/>
</classpath>
</java>
</target>
<target name="init-cc" depends="init-cc-disabled, init-cc-enabled">
<property name="run.test.cc.jvmargs" value=""/>
</target>
<target name="init-cc-cleanup" if="${cc.enabled}">
<delete dir="${cc.dir}" failonerror="false" />
<delete dir="${build.dir}/to_be_instrumented" failonerror="false" />
</target>
<target name="check-merging-files" depends="init">
<resourcecount property="cc.xmls">
<filelist dir="${cc.dir}" files="*.xml" />
</resourcecount>
<echo message="checking avalibility of ${cc.template}"/>
<condition property="nothing-to-merge" value="true">
<equals arg1="${cc.xmls}" arg2="1" trim="true"/>
<not>
<available file="${cc.template}"/>
</not>
</condition>
<echo message="nothing-to-merge = ${nothing-to-merge}"/>
</target>
<target name="fix-merging-files" depends="check-merging-files" if="${nothing-to-merge}">
<echo message="making pre-merge workaround"/>
<echo message="making pre-merge workaround due to missed template"/>
<move todir="${cc.dir}" includeemptydirs="false">
<fileset dir="${cc.dir}">
<include name="*.xml"/>
......@@ -81,12 +127,12 @@
<target name="merge-code-coverage" depends="fix-merging-files" unless="${nothing-to-merge}">
<echo message="merging files"/>
<fileset dir="${cc.dir}" id="cc.xmls">
<include name="**/*${jcov}*.xml"/>
<include name="**/*_${jcov}_*.xml"/>
<include name="**/CC_template.xml"/>
</fileset>
<pathconvert pathsep=" " property="cc.all.xmls" refid="cc.xmls"/>
<echo message="merging files - ${cc.all.xmls}" />
<java classname="com.sun.tdk.jcov.Merger">
<arg value="-verbose"/>
<arg value="-output"/>
......
......@@ -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.
......@@ -210,7 +210,7 @@ run.test.xms=2G
# 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 @@ jcov=dynamic
#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}
......@@ -46,7 +46,7 @@ import java.util.regex.Pattern;
* <p>Pattern and the logic for parameter position: java.util.Formatter
*
*/
public final class Formatter {
final class Formatter {
private Formatter() {
}
......@@ -59,8 +59,8 @@ public final class Formatter {
* @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 @@ public final class Formatter {
/**
* 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 @@ public final class Formatter {
* Method to check if a string contains '&lt;'. This is used to find out if
* previous parameter is used.
*
* @param s
* @param s string to check
* @return true if '&lt;' is in the string, else false
*/
private static boolean isPreviousArgument(final String s) {
......
......@@ -32,6 +32,7 @@ import java.io.IOException;
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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
private <T> T getInterfaceInner(final Object self, final Class<T> 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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
setContextVariables(ctxt);
final Object val = ctxt.getAttribute(ScriptEngine.FILENAME);
final String fileName = (val != null) ? val.toString() : "<eval>";
// 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 ("<system-init>".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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
}
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();
......
......@@ -147,6 +147,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* @return newly created script engine.
*/
public ScriptEngine getScriptEngine(final ClassLoader appLoader) {
checkConfigPermission();
return new NashornScriptEngine(this, appLoader);
}
......@@ -157,6 +158,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* @return newly created script engine.
*/
public ScriptEngine getScriptEngine(final String[] args) {
checkConfigPermission();
return new NashornScriptEngine(this, args, getAppClassLoader());
}
......@@ -168,11 +170,19 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* @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<String> names;
private static final List<String> mimeTypes;
private static final List<String> extensions;
......
/*
* 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);
}
}
......@@ -46,3 +46,49 @@ function print(str) {
}
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);
}
});
......@@ -32,7 +32,6 @@ import static jdk.nashorn.internal.codegen.Condition.LE;
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;
......
......@@ -194,6 +194,14 @@ public class ClassEmitter implements Emitter {
defineCommonStatics(strictMode);
}
/**
* 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.
*
......@@ -244,7 +252,7 @@ public class ClassEmitter implements Emitter {
// $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 @@ public class ClassEmitter implements Emitter {
// $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();
......
......@@ -2,10 +2,10 @@ package jdk.nashorn.internal.codegen;
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.io.IOException;
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 @@ enum CompilationPhase {
* 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 @@ enum CompilationPhase {
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 @@ enum CompilationPhase {
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 @@ enum CompilationPhase {
* 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 @@ enum CompilationPhase {
* 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 @@ enum CompilationPhase {
* 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 @@ enum CompilationPhase {
* 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 @@ enum CompilationPhase {
* 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 @@ enum CompilationPhase {
*
* 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 @@ enum CompilationPhase {
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 @@ enum CompilationPhase {
};
private final EnumSet<CompilationState> pre;
private final CompilationState post;
private long startTime;
private long endTime;
private boolean isFinished;
private CompilationPhase(final EnumSet<CompilationState> pre) {
this(pre, null);
}
private CompilationPhase(final EnumSet<CompilationState> pre, final CompilationState post) {
this.pre = pre;
this.post = post;
this.pre = pre;
}
boolean isApplicable(final FunctionNode functionNode) {
......@@ -343,10 +359,6 @@ enum CompilationPhase {
endTime = System.currentTimeMillis();
Timing.accumulateTime(toString(), endTime - startTime);
if (post != null) {
functionNode.setState(post);
}
isFinished = true;
}
......
......@@ -37,6 +37,8 @@ public class CompileUnit {
private long weight;
private Class<?> clazz;
CompileUnit(final String className, final ClassEmitter classEmitter) {
this(className, classEmitter, 0L);
}
......@@ -47,6 +49,24 @@ public class CompileUnit {
this.weight = initialWeight;
}
/**
* 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
......
......@@ -45,11 +45,14 @@ import java.util.LinkedList;
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 @@ public final class Compiler {
/** 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<String, byte[]> bytecode;
private final Set<CompileUnit> compileUnits;
......@@ -164,7 +165,7 @@ public final class Compiler {
* 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 @@ public final class Compiler {
CompilationPhase.BYTECODE_GENERATION_PHASE);
final static CompilationSequence SEQUENCE_LAZY =
SEQUENCE_NORMAL.insertFirst(CompilationPhase.LAZY_INITIALIZATION_PHASE);
SEQUENCE_EAGER.insertFirst(CompilationPhase.LAZY_INITIALIZATION_PHASE);
private static CompilationSequence sequence(final boolean lazy) {
return lazy ? SEQUENCE_LAZY : SEQUENCE_EAGER;
}
final static CompilationSequence SEQUENCE_DEFAULT =
LAZY_JIT ?
SEQUENCE_LAZY :
SEQUENCE_NORMAL;
boolean isLazy() {
return sequence == SEQUENCE_LAZY;
}
private static String lazyTag(final FunctionNode functionNode) {
if (functionNode.isLazy()) {
......@@ -212,11 +216,6 @@ public final class Compiler {
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 @@ public final class Compiler {
* @param strict should this compilation use strict mode semantics
*/
public Compiler(final CodeInstaller<ScriptEnvironment> 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 @@ public final class Compiler {
* @param functionNode function node (in any available {@link CompilationState}) to compile
*/
public Compiler(final CodeInstaller<ScriptEnvironment> 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 @@ public final class Compiler {
* @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<Void>() {
@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 @@ public final class Compiler {
assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed";
Class<?> rootClass = null;
final Map<String, Class<?>> installedClasses = new HashMap<>();
for (final Entry<String, byte[]> entry : bytecode.entrySet()) {
final String className = entry.getKey();
LOG.fine("Installing class " + className);
final String rootClassName = firstCompileUnitName();
final byte[] rootByteCode = bytecode.get(rootClassName);
final Class<?> rootClass = install(rootClassName, rootByteCode);
final byte[] code = entry.getValue();
final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
int length = rootByteCode.length;
if (rootClass == null && firstCompileUnitName().equals(className)) {
rootClass = clazz;
installedClasses.put(rootClassName, rootClass);
for (final Entry<String, byte[]> entry : bytecode.entrySet()) {
final String className = entry.getKey();
if (className.equals(rootClassName)) {
continue;
}
final byte[] code = entry.getValue();
length += code.length;
try {
final Source source = getSource();
final Object[] constants = getConstantData().toArray();
// Need doPrivileged because these fields are private
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@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);
installedClasses.put(className, install(className, code));
}
for (final CompileUnit unit : compileUnits) {
unit.setCode(installedClasses.get(unit.getUnitClassName()));
}
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;
}
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) {
sb.append(" Install time: ").append(duration).append(" ms");
}
}
if (sb != null) {
LOG.info(sb.toString());
}
return rootClass;
......@@ -444,8 +541,6 @@ public final class Compiler {
* 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 @@ public final class Compiler {
assert !USE_INT_ARITH : "Integer arithmetic is not enabled";
}
}
......@@ -40,13 +40,14 @@ import jdk.nashorn.internal.ir.DoWhileNode;
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
// 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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override
public Node leaveDECINC(final UnaryNode unaryNode) {
specialize(unaryNode);
return unaryNode;
return specialize(unaryNode).node;
}
@Override
......@@ -158,9 +159,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
}
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
public Node leave(final RuntimeNode runtimeNode) {
public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
final List<Node> args = runtimeNode.getArgs();
for (final Node arg : args) {
assert !arg.getType().isUnknown();
......@@ -479,7 +495,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
public Node leave(final SwitchNode switchNode) {
public Node leaveSwitchNode(final SwitchNode switchNode) {
final Node expression = switchNode.getExpression();
final List<CaseNode> cases = switchNode.getCases();
final boolean allInteger = switchNode.getTag().getSymbolType().isInteger();
......@@ -498,34 +514,34 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* 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<Symbol> symbols = block.getFrame().getSymbols();
final boolean allVarsInScope = functionNode.allVarsInScope();
final boolean isVarArg = functionNode.isVarArg();
......@@ -629,10 +645,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
public Node enter(final IdentNode identNode) {
public Node enterIdentNode(final IdentNode identNode) {
if (!exclude.contains(identNode)) {
setCanBePrimitive(identNode.getSymbol());
}
......@@ -685,26 +696,36 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 <T extends Node> SpecializedNode specialize(final Assignment<T> 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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* @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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* @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 extends Node> 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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
}
LOG.info("Type override for lhs in '" + node + "' => " + to);
((TypeOverride)node).setType(to);
return ((TypeOverride<T>)node).setType(to);
}
/**
......@@ -814,8 +836,8 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
} 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);
}
......
......@@ -30,6 +30,8 @@ import jdk.nashorn.internal.ir.BinaryNode;
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 @@ final class FoldConstants extends NodeVisitor {
}
@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 @@ final class FoldConstants extends NodeVisitor {
}
@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 @@ final class FoldConstants extends NodeVisitor {
}
@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 @@ final class FoldConstants extends NodeVisitor {
}
@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();
......
......@@ -146,7 +146,7 @@ public final class FunctionSignature {
/**
* 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 @@ public final class FunctionSignature {
true,
functionNode.needsCallee(),
functionNode.getReturnType(),
(functionNode.isVarArg() && !functionNode.isScript()) ?
(functionNode.isVarArg() && !functionNode.isProgram()) ?
null :
functionNode.getParameters());
}
......@@ -202,6 +202,14 @@ public final class FunctionSignature {
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++) {
......
......@@ -651,11 +651,10 @@ public class MethodEmitter implements Emitter {
/**
* 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;
}
......
......@@ -647,21 +647,20 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
}
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);
}
}
......
......@@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.Source;
* IR representation of a property access (period operator.)
*
*/
public class AccessNode extends BaseNode implements TypeOverride {
public class AccessNode extends BaseNode implements TypeOverride<AccessNode> {
/** Property ident. */
private IdentNode property;
......@@ -56,9 +56,7 @@ public class AccessNode extends BaseNode implements TypeOverride {
super(source, token, finish, base);
this.start = base.getStart();
this.property = property;
this.property.setIsPropertyName();
this.property = property.setIsPropertyName();
}
/**
......@@ -106,10 +104,10 @@ public class AccessNode extends BaseNode implements TypeOverride {
*/
@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 @@ public class AccessNode extends BaseNode implements TypeOverride {
}
@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
......
......@@ -46,4 +46,11 @@ public interface Assignment<D extends Node> {
* @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);
}
......@@ -38,6 +38,8 @@ public abstract class BaseNode extends Node implements FunctionCall {
/** Base Node. */
protected Node base;
private boolean function;
/**
* Constructor
*
......@@ -96,6 +98,15 @@ public abstract class BaseNode extends Node implements FunctionCall {
@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;
}
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册