8131929: Add option for debuggable scopes
authorhannesw
Wed, 18 Nov 2015 17:12:47 +0100
changeset 33888 0c7b0ab328e0
parent 33887 eada6f25df36
child 33889 d12616b2b375
8131929: Add option for debuggable scopes Reviewed-by: attila, lagergren
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDebug.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties
nashorn/test/script/basic/JDK-8131929.js
nashorn/test/script/basic/JDK-8131929_prototype.js
nashorn/test/script/basic/JDK-8131929_prototype.js.EXPECTED
nashorn/test/script/basic/JDK-8131929_yui.js
nashorn/test/script/basic/JDK-8131929_yui.js.EXPECTED
nashorn/test/script/basic/prototype.js
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Nov 13 10:35:28 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Nov 18 17:12:47 2015 +0100
@@ -550,7 +550,10 @@
             if (swap) {
                 method.swap();
             }
-            for (int i = 0; i < depth; i++) {
+            if (depth > 1) {
+                method.load(depth);
+                method.invoke(ScriptObject.GET_PROTO_DEPTH);
+            } else {
                 method.invoke(ScriptObject.GET_PROTO);
             }
             if (swap) {
@@ -1379,7 +1382,10 @@
             return;
         }
         method.loadCompilerConstant(SCOPE);
-        for(int i = 0; i < count; ++i) {
+        if (count > 1) {
+            method.load(count);
+            method.invoke(ScriptObject.GET_PROTO_DEPTH);
+        } else {
             method.invoke(ScriptObject.GET_PROTO);
         }
         method.storeCompilerConstant(SCOPE);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Fri Nov 13 10:35:28 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Wed Nov 18 17:12:47 2015 +0100
@@ -239,7 +239,7 @@
     private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
 
     /** Does this function need to store all its variables in scope? */
-    private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL;
+    public static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL;
 
     /** 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;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDebug.java	Fri Nov 13 10:35:28 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDebug.java	Wed Nov 18 17:12:47 2015 +0100
@@ -224,6 +224,18 @@
     }
 
     /**
+     * Returns {@code true} if passed object is a function that is fully debuggable (has all vars in scope).
+     *
+     * @param self self reference
+     * @param obj  object
+     * @return true {@code obj} is a debuggable function
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static Object isDebuggableFunction(final Object self, final Object obj) {
+        return  (obj instanceof ScriptFunction && ((ScriptFunction) obj).hasAllVarsInScope());
+    }
+
+    /**
      * Returns the property listener count for a script object
      *
      * @param self self reference
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Fri Nov 13 10:35:28 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Wed Nov 18 17:12:47 2015 +0100
@@ -2941,6 +2941,10 @@
         try {
             // Create a new function block.
             body = newBlock();
+            if (env._debug_scopes) {
+                // debug scope options forces everything to be in scope
+                markEval(lc);
+            }
             assert functionNode != null;
             final int functionId = functionNode.getId();
             parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Fri Nov 13 10:35:28 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Wed Nov 18 17:12:47 2015 +0100
@@ -81,6 +81,9 @@
     /** Generate line number table in class files */
     public final boolean _debug_lines;
 
+    /** Put all variables in scopes to make them debuggable */
+    public final boolean _debug_scopes;
+
     /** Directory in which source files and generated class files are dumped */
     public final String  _dest_dir;
 
@@ -246,6 +249,7 @@
         _compile_only         = options.getBoolean("compile.only");
         _const_as_var         = options.getBoolean("const.as.var");
         _debug_lines          = options.getBoolean("debug.lines");
+        _debug_scopes         = options.getBoolean("debug.scopes");
         _dest_dir             = options.getString("d");
         _dump_on_error        = options.getBoolean("doe");
         _early_lvalue_error   = options.getBoolean("early.lvalue.error");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Fri Nov 13 10:35:28 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Nov 18 17:12:47 2015 +0100
@@ -51,6 +51,7 @@
 import jdk.nashorn.internal.codegen.ApplySpecialization;
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
+import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.objects.NativeFunction;
 import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
@@ -472,6 +473,15 @@
     }
 
     /**
+     * Is this is a function with all variables in scope?
+     * @return true if function has all
+     */
+    public boolean hasAllVarsInScope() {
+        return data instanceof RecompilableScriptFunctionData &&
+                (((RecompilableScriptFunctionData) data).getFunctionFlags() & FunctionNode.HAS_ALL_VARS_IN_SCOPE) != 0;
+    }
+
+    /**
      * Returns true if this is a non-strict, non-built-in function that requires
      * non-primitive this argument according to ECMA 10.4.3.
      *
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Nov 13 10:35:28 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Nov 18 17:12:47 2015 +0100
@@ -1244,7 +1244,7 @@
     public final ScriptObject getProto(final int n) {
         assert n > 0;
         ScriptObject p = getProto();
-        for (int i = n; i-- > 0;) {
+        for (int i = n; --i > 0;) {
             p = p.getProto();
         }
         return p;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties	Fri Nov 13 10:35:28 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties	Wed Nov 18 17:12:47 2015 +0100
@@ -77,6 +77,15 @@
     desc="Print extended help for command line flags." \
 }
 
+nashorn.option.anonymous.classes = {                      \
+    name="--anonymous-classes",                           \
+    is_undocumented=true,                                 \
+    params=[auto|true|false],                             \
+    default=auto,                                         \
+    type=string,                                          \
+    desc="Use VM anonymous classes for compiled scripts." \
+}
+
 nashorn.option.class.cache.size ={                            \
     name="--class-cache-size",                                \
     short_name="-ccs",                                        \
@@ -118,6 +127,31 @@
     type=String                                                  \
 }
 
+nashorn.option.D = {                                                          \
+    name="-D",                                                                \
+    desc="-Dname=value. Set a system property. This option can be repeated.", \
+    type=String                                                               \
+}
+
+nashorn.option.debug.lines = {                          \
+    name="--debug-lines",                               \
+    is_undocumented=true,                               \
+    desc="Generate line number table in .class files.", \
+    default=true                                        \
+}
+
+nashorn.option.debug.locals = {                           \
+    name="--debug-locals",                                \
+    is_undocumented=true,                                 \
+    desc="Generate local variable table in .class files." \
+}
+
+nashorn.option.debug.scopes = {                                 \
+    name="--debug-scopes",                                      \
+    is_undocumented=true,                                       \
+    desc="Put all variables in scopes to make them debuggable." \
+}
+
 nashorn.option.doe = {                   \
     name="-dump-on-error",               \
     short_name="-doe",                   \
@@ -172,6 +206,14 @@
     default=false                               \
 }
 
+nashorn.option.language = {                      \
+    name="--language",                           \
+    type=String,                                 \
+    params=[es5|es6],                            \
+    default=es5,                                 \
+    desc="Specify ECMAScript language version."  \
+}
+
 nashorn.option.log = {                                                       \
     name="--log",                                                            \
     is_undocumented=true,                                                    \
@@ -181,19 +223,6 @@
     type=Log                                                                 \
 }
 
-nashorn.option.debug.lines = {                          \
-    name="--debug-lines",                               \
-    is_undocumented=true,                               \
-    desc="Generate line number table in .class files.", \
-    default=true                                        \
-}
-
-nashorn.option.debug.locals = {                           \
-    name="--debug-locals",                                \
-    is_undocumented=true,                                 \
-    desc="Generate local variable table in .class files." \
-}
-
 nashorn.option.lazy.compilation = {                                                                      \
     name="--lazy-compilation",                                                                           \
     is_undocumented=true,                                                                                \
@@ -201,13 +230,6 @@
     default=true                                   \
 }
 
-nashorn.option.optimistic.types = {                                                                      \
-    name="--optimistic-types",                                                                           \
-    short_name="-ot",                                                                                    \
-    desc="Use optimistic type assumptions with deoptimizing recompilation. This makes the compiler try, for any program symbol whose type cannot be proven at compile time, to type it as narrow and primitive as possible. If the runtime encounters an error because symbol type is too narrow, a wider method will be generated until steady stage is reached. While this produces as optimal Java Bytecode as possible, erroneous type guesses will lead to longer warmup. Optimistic typing is currently enabled by default, but can be disabled for faster startup performance.",                     \
-    default=true                                                                                         \
-}
-
 nashorn.option.loader.per.compile = {              \
     name="--loader-per-compile",                   \
     is_undocumented=true,                          \
@@ -239,6 +261,13 @@
     default=false                                  \
 }
 
+nashorn.option.optimistic.types = {                                                                      \
+    name="--optimistic-types",                                                                           \
+    short_name="-ot",                                                                                    \
+    desc="Use optimistic type assumptions with deoptimizing recompilation. This makes the compiler try, for any program symbol whose type cannot be proven at compile time, to type it as narrow and primitive as possible. If the runtime encounters an error because symbol type is too narrow, a wider method will be generated until steady stage is reached. While this produces as optimal Java Bytecode as possible, erroneous type guesses will lead to longer warmup. Optimistic typing is currently enabled by default, but can be disabled for faster startup performance.",                     \
+    default=true                                                                                         \
+}
+
 nashorn.option.parse.only = {       \
     name="--parse-only",            \
     is_undocumented=true,           \
@@ -313,12 +342,6 @@
     desc="Print the symbol table." \
 }
 
-nashorn.option.D = {                                                          \
-    name="-D",                                                                \
-    desc="-Dname=value. Set a system property. This option can be repeated.", \
-    type=String                                                               \
-}
-
 nashorn.option.strict = {              \
     name="-strict",                    \
     desc="Run scripts in strict mode." \
@@ -329,14 +352,6 @@
     desc="Enable scripting features."   \
 }
 
-nashorn.option.language = {                      \
-    name="--language",                           \
-    type=String,                                 \
-    params=[es5|es6],                            \
-    default=es5,                                 \
-    desc="Specify ECMAScript language version."  \
-}
-
 nashorn.option.stdout = {                                                \
     name="--stdout",                                                     \
     is_undocumented=true,                                                \
@@ -380,20 +395,11 @@
     enterexit [trace callsite enter/exit], objects [print object properties]."   \
 }
 
-nashorn.option.anonymous.classes = {                      \
-    name="--anonymous-classes",                           \
-    is_undocumented=true,                                 \
-    params=[auto|true|false],                             \
-    default=auto,                                         \
-    type=string,                                          \
-    desc="Use VM anonymous classes for compiled scripts." \
-}
-
 nashorn.option.unstable.relink.threshold ={                   \
     name="--unstable-relink-threshold",                       \
     short_name="-urt",                                        \
-    desc="Number of times a dynamic call site has to be \
-    relinked before it is considered unstable, when the \
+    desc="Number of times a dynamic call site has to be       \
+    relinked before it is considered unstable, when the       \
     runtime will try to link it as if it is megamorphic.",    \
     is_undocumented=true,                                     \
     type=Integer,                                             \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8131929.js	Wed Nov 18 17:12:47 2015 +0100
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8131929: Add option for debuggable scopes
+ *
+ * @test
+ * @run
+ * @option --debug-scopes=true
+ * @option -Dnashorn.debug
+ * @fork
+ */
+
+
+function f1(x, y) {
+    var a = x * 2 , b = y + 3;
+    print(a, b);
+    return a + b;
+}
+
+function f2() {}
+
+Assert.assertTrue(Debug.isDebuggableFunction(f1));
+Assert.assertTrue(Debug.isDebuggableFunction(f2));
+Assert.assertTrue(Debug.isDebuggableFunction((function() { return function() {}})()));
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8131929_prototype.js	Wed Nov 18 17:12:47 2015 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8131929: Add option for debuggable scopes
+ *
+ * @test
+ * @runif external.prototype
+ * @option --debug-scopes=true
+ * @fork
+ */
+
+load(__DIR__ + 'prototype.js');
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8131929_prototype.js.EXPECTED	Wed Nov 18 17:12:47 2015 +0100
@@ -0,0 +1,1 @@
+parsed and compiled ok prototype.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8131929_yui.js	Wed Nov 18 17:12:47 2015 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8131929: Add option for debuggable scopes
+ *
+ * @test
+ * @runif external.yui
+ * @option --debug-scopes=true
+ * @fork
+ */
+
+load(__DIR__ + 'yui.js');
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8131929_yui.js.EXPECTED	Wed Nov 18 17:12:47 2015 +0100
@@ -0,0 +1,2 @@
+parsed and compiled ok yui-min.js
+parsed and compiled ok yui.js
--- a/nashorn/test/script/basic/prototype.js	Fri Nov 13 10:35:28 2015 -0800
+++ b/nashorn/test/script/basic/prototype.js	Wed Nov 18 17:12:47 2015 +0100
@@ -22,7 +22,7 @@
  */
 
 /**
- * NASHORN-467 - check that prootype.js parses and compiles
+ * NASHORN-467 - check that prototype.js parses and compiles
  *
  * @test
  * @runif external.prototype