--- a/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java Mon Jun 09 16:00:06 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java Wed Jun 11 08:53:35 2014 +0530
@@ -25,14 +25,21 @@
package jdk.nashorn.internal.runtime;
+import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Field;
+import java.net.URL;
import java.util.HashSet;
import java.util.Set;
+import jdk.nashorn.internal.scripts.JS;
/**
* This class provides support for external debuggers. Its primary purpose is
* is to simplify the debugger tasks and provide better performance.
+ * Even though the methods are not public, there are still part of the
+ * external debugger interface.
*/
final class DebuggerSupport {
/**
@@ -49,6 +56,11 @@
@SuppressWarnings("unused")
final
DebuggerValueDesc forceLoad = new DebuggerValueDesc(null, false, null, null);
+
+ // Hook to force the loading of the SourceInfo class
+ @SuppressWarnings("unused")
+ final
+ SourceInfo srcInfo = new SourceInfo(null, 0, null, null);
}
/** This class is used to send a bulk description of a value. */
@@ -73,6 +85,54 @@
}
}
+ static class SourceInfo {
+ final String name;
+ final URL url;
+ final int hash;
+ final char[] content;
+
+ SourceInfo(final String name, final int hash, final URL url, final char[] content) {
+ this.name = name;
+ this.hash = hash;
+ this.url = url;
+ this.content = content;
+ }
+ }
+
+ /**
+ * Hook that is called just before invoking method handle
+ * from ScriptFunctionData via invoke, constructor method calls.
+ *
+ * @param mh script class method about to be invoked.
+ */
+ static void notifyInvoke(final MethodHandle mh) {
+ // Do nothing here. This is placeholder method on which a
+ // debugger can place a breakpoint so that it can access the
+ // (script class) method handle that is about to be invoked.
+ // See ScriptFunctionData.invoke and ScriptFunctionData.construct.
+ }
+
+ /**
+ * Return the script source info for the given script class.
+ *
+ * @param clazz compiled script class
+ * @return SourceInfo
+ */
+ static SourceInfo getSourceInfo(final Class<?> clazz) {
+ if (JS.class.isAssignableFrom(clazz)) {
+ try {
+ final Field sourceField = clazz.getDeclaredField(SOURCE.symbolName());
+ sourceField.setAccessible(true);
+ final Source src = (Source) sourceField.get(null);
+ return src.getSourceInfo();
+ } catch (final IllegalAccessException | NoSuchFieldException ignored) {
+ return null;
+ }
+ }
+
+ return null;
+ }
+
/**
* Return the current context global.
* @return context global.
@@ -87,7 +147,7 @@
* @param self Receiver to use.
* @param string String to evaluate.
* @param returnException true if exceptions are to be returned.
- * @return Result of eval as string, or, an exception or null depending on returnException.
+ * @return Result of eval, or, an exception or null depending on returnException.
*/
static Object eval(final ScriptObject scope, final Object self, final String string, final boolean returnException) {
final ScriptObject global = Context.getGlobal();
@@ -238,7 +298,7 @@
* @param value Arbitrary value to be displayed by the debugger.
* @return A string representation of the value or an array of DebuggerValueDesc.
*/
- private static String valueAsString(final Object value) {
+ static String valueAsString(final Object value) {
final JSType type = JSType.of(value);
switch (type) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Mon Jun 09 16:00:06 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed Jun 11 08:53:35 2014 +0530
@@ -551,6 +551,8 @@
final Object selfObj = convertThisObject(self);
final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
+ DebuggerSupport.notifyInvoke(mh);
+
if (isVarArg(mh)) {
if (needsCallee(mh)) {
return mh.invokeExact(fn, selfObj, args);
@@ -604,6 +606,8 @@
final MethodHandle mh = getGenericConstructor(fn.getScope());
final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
+ DebuggerSupport.notifyInvoke(mh);
+
if (isVarArg(mh)) {
if (needsCallee(mh)) {
return mh.invokeExact(fn, args);
--- a/nashorn/src/jdk/nashorn/internal/runtime/Source.java Mon Jun 09 16:00:06 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Source.java Wed Jun 11 08:53:35 2014 +0530
@@ -126,6 +126,11 @@
}
}
+ /* package-private */
+ DebuggerSupport.SourceInfo getSourceInfo() {
+ return new DebuggerSupport.SourceInfo(getName(), data.hashCode(), data.url(), data.array());
+ }
+
// Wrapper to manage lazy loading
private static interface Data {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/JDK-8044798.js Wed Jun 11 08:53:35 2014 +0530
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014, 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-8044798: API for debugging Nashorn
+ *
+ * @test
+ * @run
+ */
+
+// basic API exercise checks
+
+var Arrays = Java.type("java.util.Arrays");
+var CharArray = Java.type("char[]");
+var DebuggerSupport = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport");
+var DebuggerValueDesc = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport.DebuggerValueDesc");
+
+var valueDescFields = DebuggerValueDesc.class.declaredFields;
+Arrays.sort(valueDescFields, function(f1, f2) f1.name.compareTo(f2.name));
+for each (var f in valueDescFields) {
+ f.accessible = true;
+}
+
+var debuggerSupportMethods = DebuggerSupport.class.declaredMethods;
+
+// methods of DebuggerSupport that we use
+var evalMethod, valueInfoMethod, valueInfosMethod;
+var getSourceInfoMethod, valueAsStringMethod;
+
+for each (var m in debuggerSupportMethods) {
+ m.accessible = true;
+ switch (m.name) {
+ case "eval":
+ evalMethod = m;
+ break;
+ case "valueInfo":
+ if (m.parameterCount == 3) {
+ valueInfoMethod = m;
+ }
+ break;
+ case "valueInfos":
+ valueInfosMethod = m;
+ break;
+ case "valueAsString":
+ valueAsStringMethod = m;
+ break;
+ case "getSourceInfo":
+ getSourceInfoMethod = m;
+ break;
+ }
+}
+
+// eval
+var value = evalMethod.invoke(null, null, null, "33 + 55", false);
+print(value);
+
+// valueInfo
+var info = valueInfoMethod.invoke(null, "apply", Function, true);
+for each (var f in valueDescFields) {
+ print(f.name, "=", f.get(info));
+}
+
+// valueInfo - user defined object
+var info = valueInfoMethod.invoke(null, "foo", { foo: 343 }, true);
+for each (var f in valueDescFields) {
+ print(f.name, "=", f.get(info));
+}
+
+// valueInfos
+var infos = valueInfosMethod.invoke(null, Object, true);
+for each (var info in infos) {
+ for each (var f in valueDescFields) {
+ print(f.name, "=", f.get(info));
+ }
+}
+
+// valueInfos - user defined object
+var infos = valueInfosMethod.invoke(null, { foo: 34, bar: "hello" }, true);
+for each (var info in infos) {
+ for each (var f in valueDescFields) {
+ print(f.name, "=", f.get(info));
+ }
+}
+
+// valueAsString
+function printValue(value) {
+ print(valueAsStringMethod.invoke(null, value));
+}
+
+printValue(undefined);
+printValue(null);
+printValue("hello");
+printValue(Math.PI);
+printValue(this);
+
+// The below are not part of DebuggerSupport. But we need these to
+// test DebuggerSupport.getSourceInfo etc. which need compiled script class
+
+var Source = Java.type("jdk.nashorn.internal.runtime.Source");
+var Context = Java.type("jdk.nashorn.internal.runtime.Context");
+var sourceCls = Source.class;
+var errorMgrCls = Java.type("jdk.nashorn.internal.runtime.ErrorManager").class;
+var booleanCls = Java.type("java.lang.Boolean").TYPE;
+
+// private compile method of Context class
+var compileMethod = Context.class.getDeclaredMethod("compile",
+ sourceCls, errorMgrCls, booleanCls);
+compileMethod.accessible = true;
+
+var scriptCls = compileMethod.invoke(Context.context,
+ Source.sourceFor("test", "print('hello')"),
+ new Context.ThrowErrorManager(), false);
+
+var SCRIPT_CLASS_NAME_PREFIX = "jdk.nashorn.internal.scripts.Script$";
+print("script class name pattern satisfied? " +
+ scriptCls.name.startsWith(SCRIPT_CLASS_NAME_PREFIX));
+
+var srcInfo = getSourceInfoMethod.invoke(null, scriptCls);
+var srcInfoFields = srcInfo.class.declaredFields;
+Arrays.sort(srcInfoFields, function(f1, f2) f1.name.compareTo(f2.name));
+
+print("Source info");
+for each (var f in srcInfoFields) {
+ f.accessible = true;
+ var fieldValue = f.get(srcInfo);
+ if (fieldValue instanceof CharArray) {
+ fieldValue = new java.lang.String(fieldValue);
+ }
+
+ print(f.name, "=", fieldValue);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/JDK-8044798.js.EXPECTED Wed Jun 11 08:53:35 2014 +0530
@@ -0,0 +1,104 @@
+88
+expandable = false
+key = apply
+valueAsObject = function Function() { [native code] }
+valueAsString = function Function() { [native code] }
+expandable = true
+key = foo
+valueAsObject = [object Object]
+valueAsString = {foo: 343}
+expandable = false
+key = setIndexedPropertiesToExternalArrayData
+valueAsObject = function setIndexedPropertiesToExternalArrayData() { [native code] }
+valueAsString = function setIndexedPropertiesToExternalArrayData() { [native code] }
+expandable = false
+key = getPrototypeOf
+valueAsObject = function getPrototypeOf() { [native code] }
+valueAsString = function getPrototypeOf() { [native code] }
+expandable = false
+key = setPrototypeOf
+valueAsObject = function setPrototypeOf() { [native code] }
+valueAsString = function setPrototypeOf() { [native code] }
+expandable = false
+key = getOwnPropertyDescriptor
+valueAsObject = function getOwnPropertyDescriptor() { [native code] }
+valueAsString = function getOwnPropertyDescriptor() { [native code] }
+expandable = false
+key = getOwnPropertyNames
+valueAsObject = function getOwnPropertyNames() { [native code] }
+valueAsString = function getOwnPropertyNames() { [native code] }
+expandable = false
+key = create
+valueAsObject = function create() { [native code] }
+valueAsString = function create() { [native code] }
+expandable = false
+key = defineProperty
+valueAsObject = function defineProperty() { [native code] }
+valueAsString = function defineProperty() { [native code] }
+expandable = false
+key = defineProperties
+valueAsObject = function defineProperties() { [native code] }
+valueAsString = function defineProperties() { [native code] }
+expandable = false
+key = seal
+valueAsObject = function seal() { [native code] }
+valueAsString = function seal() { [native code] }
+expandable = false
+key = freeze
+valueAsObject = function freeze() { [native code] }
+valueAsString = function freeze() { [native code] }
+expandable = false
+key = preventExtensions
+valueAsObject = function preventExtensions() { [native code] }
+valueAsString = function preventExtensions() { [native code] }
+expandable = false
+key = isSealed
+valueAsObject = function isSealed() { [native code] }
+valueAsString = function isSealed() { [native code] }
+expandable = false
+key = isFrozen
+valueAsObject = function isFrozen() { [native code] }
+valueAsString = function isFrozen() { [native code] }
+expandable = false
+key = isExtensible
+valueAsObject = function isExtensible() { [native code] }
+valueAsString = function isExtensible() { [native code] }
+expandable = false
+key = keys
+valueAsObject = function keys() { [native code] }
+valueAsString = function keys() { [native code] }
+expandable = false
+key = bindProperties
+valueAsObject = function bindProperties() { [native code] }
+valueAsString = function bindProperties() { [native code] }
+expandable = false
+key = prototype
+valueAsObject = [object Object]
+valueAsString = {toString: function toString() { [native code] }, toLocaleString: function toLocaleString() { [native code] }, valueOf: function valueOf() { [native code] }, hasOwnProperty: function hasOwnProperty() { [native code] }, isPrototypeOf: function isPrototypeOf() { [native code] }, propertyIsEnumerable: function propertyIsEnumerable() { [native code] }, constructor: function Object() { [native code] }, __proto__: null}
+expandable = false
+key = length
+valueAsObject = 1
+valueAsString = 1
+expandable = false
+key = name
+valueAsObject = Object
+valueAsString = "Object"
+expandable = false
+key = foo
+valueAsObject = 34
+valueAsString = 34
+expandable = false
+key = bar
+valueAsObject = hello
+valueAsString = "hello"
+undefined
+null
+"hello"
+3.141592653589793
+[object global]
+script class name pattern satisfied? true
+Source info
+content = print('hello')
+hash = 1655359881
+name = test
+url = null
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/debuggersupportapi.js Wed Jun 11 08:53:35 2014 +0530
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, 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-8044798: API for debugging Nashorn
+ *
+ * @test
+ * @run
+ */
+
+// Basic API class, method, field existence checks.
+
+// The following classes and the associated methods and fields are used as
+// private debugger interface. Though private/implementation defined, nashorn
+// code should not be changed to remove these classes, fields and methods.
+// The test takes signatures of debugger interface and stores in .EXPECTED file.
+// If any incompatible change is made to nashorn to break any of these, this
+// test will fail.
+
+var Arrays = Java.type("java.util.Arrays");
+var DebuggerSupport = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport");
+
+print(DebuggerSupport.class);
+print();
+var methods = DebuggerSupport.class.declaredMethods;
+Arrays.sort(methods, function(m1, m2) m1.name.compareTo(m2.name));
+for each (var mth in methods) {
+ switch (mth.name) {
+ case "eval":
+ case "notifyInvoke":
+ case "getSourceInfo":
+ case "valueAsString":
+ case "valueInfos":
+ print(mth);
+ break;
+ case "valueInfo":
+ if (mth.parameterCount == 3) {
+ print(mth);
+ }
+ break;
+ }
+}
+print();
+
+var DebuggerValueDesc = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport.DebuggerValueDesc");
+print(DebuggerValueDesc.class);
+print();
+var fields = DebuggerValueDesc.class.declaredFields;
+Arrays.sort(fields, function(f1, f2) f1.name.compareTo(f2.name));
+for each (var fld in fields) {
+ switch (fld.name) {
+ case "key":
+ case "expandable":
+ case "valueAsObject":
+ case "valueAsString":
+ print(fld);
+ }
+}
+print();
+
+var SourceInfo = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport.SourceInfo");
+print(SourceInfo.class);
+print();
+var fields = SourceInfo.class.declaredFields;
+Arrays.sort(fields, function(f1, f2) f1.name.compareTo(f2.name));
+for each (var fld in fields) {
+ switch (fld.name) {
+ case "name":
+ case "hash":
+ case "url":
+ case "content":
+ print(fld);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/debuggersupportapi.js.EXPECTED Wed Jun 11 08:53:35 2014 +0530
@@ -0,0 +1,22 @@
+class jdk.nashorn.internal.runtime.DebuggerSupport
+
+static java.lang.Object jdk.nashorn.internal.runtime.DebuggerSupport.eval(jdk.nashorn.internal.runtime.ScriptObject,java.lang.Object,java.lang.String,boolean)
+static jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo jdk.nashorn.internal.runtime.DebuggerSupport.getSourceInfo(java.lang.Class)
+static void jdk.nashorn.internal.runtime.DebuggerSupport.notifyInvoke(java.lang.invoke.MethodHandle)
+static java.lang.String jdk.nashorn.internal.runtime.DebuggerSupport.valueAsString(java.lang.Object)
+static jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc jdk.nashorn.internal.runtime.DebuggerSupport.valueInfo(java.lang.String,java.lang.Object,boolean)
+static jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc[] jdk.nashorn.internal.runtime.DebuggerSupport.valueInfos(java.lang.Object,boolean)
+
+class jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc
+
+final boolean jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc.expandable
+final java.lang.String jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc.key
+final java.lang.Object jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc.valueAsObject
+final java.lang.String jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc.valueAsString
+
+class jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo
+
+final char[] jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo.content
+final int jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo.hash
+final java.lang.String jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo.name
+final java.net.URL jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo.url