changeset 138:390d44ba90cf

8009982: Lazy execution bugfix. Added lazy sunspider unit test. Added mandreel to compile-octane test. Fixed warnings Reviewed-by: sundar, jlaskey
author lagergren
date Thu, 14 Mar 2013 14:49:55 +0100
parents 60684aeba89c
children d5d80b52cf1c
files src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java src/jdk/nashorn/internal/codegen/CodeGenerator.java src/jdk/nashorn/internal/codegen/Compiler.java src/jdk/nashorn/internal/ir/FunctionNode.java src/jdk/nashorn/internal/objects/Global.java src/jdk/nashorn/internal/parser/Parser.java src/jdk/nashorn/internal/runtime/Context.java src/jdk/nashorn/internal/runtime/ScriptLoader.java src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java src/jdk/nashorn/internal/runtime/regexp/RegExp.java src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java test/script/basic/compile-octane.js.EXPECTED test/script/basic/run-octane.js test/script/basic/runsunspider-eager.js test/script/basic/runsunspider-lazy.js test/script/basic/runsunspider.js
diffstat 20 files changed, 152 insertions(+), 75 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Thu Mar 14 14:49:55 2013 +0100
@@ -176,7 +176,7 @@
 
     // -- 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"));
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Mar 14 14:49:55 2013 +0100
@@ -3230,8 +3230,7 @@
     }
 
     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 @@
                 } else {
                     m.loadNull();
                 }
-                m.invoke(constructorNoLookup(className, cparams));
+                m.invoke(constructorNoLookup(className, RecompilableScriptFunctionData.class, ScriptObject.class));
             }
         }.makeObject(method);
     }
--- a/src/jdk/nashorn/internal/codegen/Compiler.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Thu Mar 14 14:49:55 2013 +0100
@@ -217,8 +217,6 @@
                 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 @@
         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 @@
             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 @@
             }
         });
 
-        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;
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Thu Mar 14 14:49:55 2013 +0100
@@ -218,8 +218,9 @@
     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 @@
      * 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 @@
         } else {
             this.flags |= USES_ANCESTOR_SCOPE;
             final FunctionNode parentFn = findParentFunction();
-            if(parentFn != null) {
+            if (parentFn != null) {
                 parentFn.setUsesScopeSymbol(symbol);
             }
         }
--- a/src/jdk/nashorn/internal/objects/Global.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/objects/Global.java	Thu Mar 14 14:49:55 2013 +0100
@@ -1528,8 +1528,9 @@
         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 {
--- a/src/jdk/nashorn/internal/parser/Parser.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/parser/Parser.java	Thu Mar 14 14:49:55 2013 +0100
@@ -126,7 +126,7 @@
     /** 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
--- a/src/jdk/nashorn/internal/runtime/Context.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/runtime/Context.java	Thu Mar 14 14:49:55 2013 +0100
@@ -744,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;
             }
         }
--- a/src/jdk/nashorn/internal/runtime/ScriptLoader.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/runtime/ScriptLoader.java	Thu Mar 14 14:49:55 2013 +0100
@@ -60,8 +60,7 @@
     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);
     }
 }
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java	Thu Mar 14 14:49:55 2013 +0100
@@ -412,6 +412,7 @@
     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,
--- a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java	Thu Mar 14 14:49:55 2013 +0100
@@ -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 {
--- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java	Thu Mar 14 14:49:55 2013 +0100
@@ -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;
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExp.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExp.java	Thu Mar 14 14:49:55 2013 +0100
@@ -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));
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java	Thu Mar 14 14:49:55 2013 +0100
@@ -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) {
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java	Thu Mar 14 14:49:55 2013 +0100
@@ -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] : "";
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java	Tue Mar 12 21:17:47 2013 +0530
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java	Thu Mar 14 14:49:55 2013 +0100
@@ -182,8 +182,6 @@
      * @return Committed token
      */
     private boolean commit(final int n) {
-        final int startIn = position;
-
         switch (n) {
         case 1:
             sb.append(ch0);
--- a/test/script/basic/compile-octane.js.EXPECTED	Tue Mar 12 21:17:47 2013 +0530
+++ b/test/script/basic/compile-octane.js.EXPECTED	Thu Mar 14 14:49:55 2013 +0100
@@ -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
 
--- a/test/script/basic/run-octane.js	Tue Mar 12 21:17:47 2013 +0530
+++ b/test/script/basic/run-octane.js	Thu Mar 14 14:49:55 2013 +0100
@@ -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);
     }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/runsunspider-eager.js	Thu Mar 14 14:49:55 2013 +0100
@@ -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");
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/runsunspider-lazy.js	Thu Mar 14 14:49:55 2013 +0100
@@ -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");
+
--- a/test/script/basic/runsunspider.js	Tue Mar 12 21:17:47 2013 +0530
+++ b/test/script/basic/runsunspider.js	Thu Mar 14 14:49:55 2013 +0100
@@ -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) {