8029364: NashornException to expose thrown object

Reviewed-by: lagergren, jlaskey
This commit is contained in:
Athijegannathan Sundararajan 2013-12-02 18:19:26 +05:30
parent ab92b2401e
commit 31006e8d33
6 changed files with 106 additions and 4 deletions

View File

@ -29,6 +29,7 @@ import java.util.ArrayList;
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 @@ public abstract class NashornException extends RuntimeException {
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 @@ public abstract class NashornException extends RuntimeException {
}
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;
}
}

View File

@ -476,16 +476,19 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
} 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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
if (cause instanceof NoSuchMethodException) {
throw (NoSuchMethodException)cause;
}
throwAsScriptException(e);
throwAsScriptException(e, invokeGlobal);
throw new AssertionError("should not reach here");
}
}
@ -543,7 +547,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
}
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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
return nashornContext.compileScript(source, newGlobal);
} catch (final Exception e) {
throwAsScriptException(e);
throwAsScriptException(e, newGlobal);
throw new AssertionError("should not reach here");
} finally {
if (globalChanged) {

View File

@ -108,6 +108,8 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
}
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 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
}
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 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
}
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 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
}
try {
return callable.call();
} catch (final NashornException ne) {
throw ne.initEcmaError(global);
} catch (final RuntimeException e) {
throw e;
} catch (final Exception e) {

View File

@ -88,6 +88,7 @@ public final class ECMAException extends NashornException {
* Get the thrown object
* @return thrown object
*/
@Override
public Object getThrown() {
return thrown;
}

View File

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

View File

@ -0,0 +1,7 @@
class javax.script.ScriptException
class jdk.nashorn.internal.runtime.ECMAException
Error: foo
true
Error
foo
33