8029364: NashornException to expose thrown object
Reviewed-by: lagergren, jlaskey
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornException.java Wed Nov 27 14:13:52 2013 +0530
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornException.java Mon Dec 02 18:19:26 2013 +0530
@@ -29,6 +29,7 @@
import java.util.List;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.runtime.ECMAErrors;
+import jdk.nashorn.internal.runtime.ScriptObject;
/**
* This is base exception for all Nashorn exceptions. These originate from
@@ -49,6 +50,8 @@
private final int line;
// script column number
private final int column;
+ // underlying ECMA error object - lazily initialized
+ private Object ecmaError;
/** script source name used for "engine.js" */
public static final String ENGINE_SCRIPT_SOURCE_NAME = "nashorn:engine/resources/engine.js";
@@ -188,4 +191,33 @@
}
return buf.toString();
}
+
+ protected Object getThrown() {
+ return null;
+ }
+
+ protected NashornException initEcmaError(final ScriptObject global) {
+ if (ecmaError != null) {
+ return this; // initialized already!
+ }
+
+ final Object thrown = getThrown();
+ if (thrown instanceof ScriptObject) {
+ ecmaError = ScriptObjectMirror.wrap(thrown, global);
+ } else {
+ ecmaError = thrown;
+ }
+
+ return this;
+ }
+
+ /**
+ * Return the underlying ECMA error object, if available.
+ *
+ * @return underlying ECMA Error object's mirror or whatever was thrown
+ * from script such as a String, Number or a Boolean.
+ */
+ public Object getEcmaError() {
+ return ecmaError;
+ }
}
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Wed Nov 27 14:13:52 2013 +0530
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Mon Dec 02 18:19:26 2013 +0530
@@ -476,16 +476,19 @@
private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
name.getClass(); // null check
+ ScriptObject invokeGlobal = null;
ScriptObjectMirror selfMirror = null;
if (selfObject instanceof ScriptObjectMirror) {
selfMirror = (ScriptObjectMirror)selfObject;
if (! isOfContext(selfMirror.getHomeGlobal(), nashornContext)) {
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
}
+ invokeGlobal = selfMirror.getHomeGlobal();
} else if (selfObject instanceof ScriptObject) {
// invokeMethod called from script code - in which case we may get 'naked' ScriptObject
// Wrap it with oldGlobal to make a ScriptObjectMirror for the same.
final ScriptObject oldGlobal = Context.getGlobal();
+ invokeGlobal = oldGlobal;
if (oldGlobal == null) {
throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
}
@@ -498,6 +501,7 @@
} else if (selfObject == null) {
// selfObject is null => global function call
final ScriptObject ctxtGlobal = getNashornGlobalFrom(context);
+ invokeGlobal = ctxtGlobal;
selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(ctxtGlobal, ctxtGlobal);
}
@@ -509,7 +513,7 @@
if (cause instanceof NoSuchMethodException) {
throw (NoSuchMethodException)cause;
}
- throwAsScriptException(e);
+ throwAsScriptException(e, invokeGlobal);
throw new AssertionError("should not reach here");
}
}
@@ -543,7 +547,7 @@
}
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
} catch (final Exception e) {
- throwAsScriptException(e);
+ throwAsScriptException(e, ctxtGlobal);
throw new AssertionError("should not reach here");
} finally {
if (globalChanged) {
@@ -552,7 +556,7 @@
}
}
- private static void throwAsScriptException(final Exception e) throws ScriptException {
+ private static void throwAsScriptException(final Exception e, final ScriptObject global) throws ScriptException {
if (e instanceof ScriptException) {
throw (ScriptException)e;
} else if (e instanceof NashornException) {
@@ -560,6 +564,7 @@
final ScriptException se = new ScriptException(
ne.getMessage(), ne.getFileName(),
ne.getLineNumber(), ne.getColumnNumber());
+ ne.initEcmaError(global);
se.initCause(e);
throw se;
} else if (e instanceof RuntimeException) {
@@ -605,7 +610,7 @@
return nashornContext.compileScript(source, newGlobal);
} catch (final Exception e) {
- throwAsScriptException(e);
+ throwAsScriptException(e, newGlobal);
throw new AssertionError("should not reach here");
} finally {
if (globalChanged) {
--- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Wed Nov 27 14:13:52 2013 +0530
+++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Mon Dec 02 18:19:26 2013 +0530
@@ -108,6 +108,8 @@
}
throw new RuntimeException("not a function: " + toString());
+ } catch (final NashornException ne) {
+ throw ne.initEcmaError(global);
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
@@ -135,6 +137,8 @@
}
throw new RuntimeException("not a constructor: " + toString());
+ } catch (final NashornException ne) {
+ throw ne.initEcmaError(global);
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
@@ -182,6 +186,8 @@
}
throw new NoSuchMethodException("No such function " + functionName);
+ } catch (final NashornException ne) {
+ throw ne.initEcmaError(global);
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
@@ -717,6 +723,8 @@
}
try {
return callable.call();
+ } catch (final NashornException ne) {
+ throw ne.initEcmaError(global);
} catch (final RuntimeException e) {
throw e;
} catch (final Exception e) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/ECMAException.java Wed Nov 27 14:13:52 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ECMAException.java Mon Dec 02 18:19:26 2013 +0530
@@ -88,6 +88,7 @@
* Get the thrown object
* @return thrown object
*/
+ @Override
public Object getThrown() {
return thrown;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8029364.js Mon Dec 02 18:19:26 2013 +0530
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8029364: NashornException to expose thrown object
+ *
+ * @test
+ * @run
+ */
+
+var m = new javax.script.ScriptEngineManager();
+var e = m.getEngineByName("nashorn");
+var g = e.eval("this");
+try {
+ e.eval("var e = new Error('foo'); e.bar = 33; throw e");
+} catch (se) {
+ // ScriptException instance's cause is a NashornException
+ print(se.getClass());
+ var cause = se.cause;
+ print(cause.getClass());
+ // NashornException instance has 'ecmaError' bean getter
+ print(cause.ecmaError);
+ // access to underlying ECMA Error object
+ print(cause.ecmaError instanceof g.Error);
+ print(cause.ecmaError.name);
+ print(cause.ecmaError.message);
+ print(cause.ecmaError.bar);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8029364.js.EXPECTED Mon Dec 02 18:19:26 2013 +0530
@@ -0,0 +1,7 @@
+class javax.script.ScriptException
+class jdk.nashorn.internal.runtime.ECMAException
+Error: foo
+true
+Error
+foo
+33