8009982: Lazy execution bugfix. Added lazy sunspider unit test. Added mandreel to compile-octane test. Fixed warnings

Reviewed-by: sundar, jlaskey
This commit is contained in:
Marcus Lagergren 2013-03-14 14:49:55 +01:00
parent d671cda73c
commit 2aeaf10fff
20 changed files with 152 additions and 75 deletions

View File

@ -176,7 +176,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
// -- Internals only below this point
private void checkConfigPermission() {
private static void checkConfigPermission() {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("nashorn.setConfig"));

View File

@ -3230,8 +3230,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
private void newFunctionObject(final FunctionNode functionNode) {
final boolean isLazy = functionNode.isLazy();
final Class<?>[] cparams = new Class<?>[] { RecompilableScriptFunctionData.class, ScriptObject.class };
final boolean isLazy = functionNode.isLazy();
new ObjectCreator(this, new ArrayList<String>(), new ArrayList<Symbol>(), false, false) {
@Override
@ -3246,7 +3245,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
} else {
m.loadNull();
}
m.invoke(constructorNoLookup(className, cparams));
m.invoke(constructorNoLookup(className, RecompilableScriptFunctionData.class, ScriptObject.class));
}
}.makeObject(method);
}

View File

@ -217,8 +217,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() + "' lazy=" + functionNode.isLazy());
}
/**
@ -361,7 +359,10 @@ public final class Compiler {
final Map<String, Class<?>> installedClasses = new HashMap<>();
final String rootClassName = firstCompileUnitName();
final Class<?> rootClass = install(rootClassName, bytecode.get(rootClassName));
final byte[] rootByteCode = bytecode.get(rootClassName);
final Class<?> rootClass = install(rootClassName, rootByteCode);
int length = rootByteCode.length;
installedClasses.put(rootClassName, rootClass);
@ -370,7 +371,10 @@ public final class Compiler {
if (className.equals(rootClassName)) {
continue;
}
installedClasses.put(className, install(className, entry.getValue()));
final byte[] code = entry.getValue();
length += code.length;
installedClasses.put(className, install(className, code));
}
for (final CompileUnit unit : compileUnits) {
@ -388,12 +392,32 @@ public final class Compiler {
}
});
LOG.info("Installed root class: " + rootClass + " and " + bytecode.size() + " compile unit classes");
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);
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;

View File

@ -218,8 +218,9 @@ public class FunctionNode extends Block {
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;
@ -724,13 +725,10 @@ public class FunctionNode extends Block {
* 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.
*
* We also conservatively need a callee if we have lazy children, i.e. nested function nodes that have not yet
* been evaluated. _They_ may need the callee and we don't know it
*
* @return true if the function's generated Java method needs a {@code callee} parameter.
*/
public boolean needsCallee() {
return hasLazyChildren() || needsParentScope() || needsSelfSymbol() || (needsArguments() && !isStrictMode());
return needsParentScope() || needsSelfSymbol() || (needsArguments() && !isStrictMode());
}
/**
@ -1076,7 +1074,7 @@ public class FunctionNode extends Block {
} else {
this.flags |= USES_ANCESTOR_SCOPE;
final FunctionNode parentFn = findParentFunction();
if(parentFn != null) {
if (parentFn != null) {
parentFn.setUsesScopeSymbol(symbol);
}
}

View File

@ -1528,8 +1528,9 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
}
private void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) {
private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
for (Field f : scriptEnv.getClass().getFields()) {
try {

View File

@ -126,7 +126,7 @@ public class Parser extends AbstractParser {
/** 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

View File

@ -744,6 +744,7 @@ public final class Context {
global = (GlobalObject)Context.getGlobalTrusted();
script = global.findCachedClass(source);
if (script != null) {
Compiler.LOG.fine("Code cache hit for " + source + " avoiding recompile.");
return script;
}
}

View File

@ -60,8 +60,7 @@ final class ScriptLoader extends NashornLoader {
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)));
} else {
return defineClass(name, data, 0, data.length, cs);
}
return defineClass(name, data, 0, data.length, cs);
}
}

View File

@ -412,6 +412,7 @@ public final class JavaAdapterFactory {
public static MethodHandle getConstructor(final Class<?> sourceType, final Class<?> targetType) throws Exception {
final StaticClass adapterClass = getAdapterClassFor(new Class<?>[] { targetType });
return AccessController.doPrivileged(new PrivilegedExceptionAction<MethodHandle>() {
@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,

View File

@ -95,14 +95,14 @@ public class DefaultRegExp extends RegExp {
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 {

View File

@ -97,14 +97,14 @@ public class JoniRegExp extends RegExp {
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;
}
/**

View File

@ -156,7 +156,7 @@ public abstract class RegExp {
*
* @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));

View File

@ -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 @@ import jdk.nashorn.internal.runtime.options.Options;
*/
public class RegExpFactory {
private final static RegExpFactory instance;
private final static String JDK = "jdk";
@ -60,7 +58,8 @@ public class RegExpFactory {
* 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 @@ public class RegExpFactory {
* 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) {

View File

@ -80,11 +80,11 @@ public final class RegExpResult {
/**
* 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] : "";
}
/**

View File

@ -182,8 +182,6 @@ final class RegExpScanner extends Scanner {
* @return Committed token
*/
private boolean commit(final int n) {
final int startIn = position;
switch (n) {
case 1:
sb.append(ch0);

View File

@ -16,6 +16,9 @@ Compiled OK: earley-boyer.js
Compiling... gbemu.js
Compiled OK: gbemu.js
Compiling... mandreel.js
Compiled OK: mandreel.js
Compiling... navier-stokes.js
Compiled OK: navier-stokes.js

View File

@ -31,7 +31,8 @@ var tests = [
"crypto.js",
"deltablue.js",
"earley-boyer.js",
"gbemu.js",
"gbemu.js",
"mandreel.js",
"navier-stokes.js",
"pdfjs.js",
"raytrace.js",
@ -49,6 +50,12 @@ var ignoreTeardown = [
{ 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 @@ function endsWith(str, suffix) {
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 @@ function run_one_benchmark(arg, iters) {
}
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_one_benchmark(arg, iters) {
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);
}
}

View File

@ -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");

View File

@ -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");

View File

@ -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) {