Reorganization of Java and JavaScript exception iteraction. See http://bugzilla.mozilla.org/show_bug.cgi?id=210605 for details.

git-svn-id: svn://10.0.0.236/trunk@144384 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
igor%mir2.org
2003-07-02 16:35:51 +00:00
parent 427a1c180b
commit 6aa94c183c
14 changed files with 180 additions and 290 deletions

View File

@@ -84,15 +84,11 @@ public class Delegator implements Function {
*/
protected Delegator newInstance()
{
Exception ex;
try {
return (Delegator)this.getClass().newInstance();
} catch (InstantiationException e) {
ex = e;
} catch (IllegalAccessException e) {
ex = e;
} catch (Exception ex) {
throw ScriptRuntime.throwAsUncheckedException(ex);
}
throw WrappedException.wrapException(ex);
}
/**

View File

@@ -413,22 +413,15 @@ public class FunctionObject extends BaseFunction {
if (method == null) Context.codeBug();
try {
result = invoker.invoke(thisObj, invokeArgs);
} catch (Exception e) {
throw JavaScriptException.wrapException(cx, scope, e);
} catch (Exception ex) {
throw ScriptRuntime.throwAsUncheckedException(ex);
}
} else {
try {
result = (method == null) ? ctor.newInstance(invokeArgs)
: method.invoke(thisObj, invokeArgs);
}
catch (InvocationTargetException e) {
throw JavaScriptException.wrapException(cx, scope, e);
}
catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
}
catch (InstantiationException e) {
throw WrappedException.wrapException(e);
} catch (Exception ex) {
throw ScriptRuntime.throwAsUncheckedException(ex);
}
}
return hasVoidReturn ? Undefined.instance : result;
@@ -447,10 +440,8 @@ public class FunctionObject extends BaseFunction {
Scriptable result;
try {
result = (Scriptable) method.getDeclaringClass().newInstance();
} catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
} catch (InstantiationException e) {
throw WrappedException.wrapException(e);
} catch (Exception ex) {
throw ScriptRuntime.throwAsUncheckedException(ex);
}
result.setPrototype(getClassPrototype());
@@ -459,7 +450,6 @@ public class FunctionObject extends BaseFunction {
}
private Object callVarargs(Context cx, Scriptable thisObj, Object[] args)
throws JavaScriptException
{
try {
if (parmsLength == VARARGS_METHOD) {
@@ -474,21 +464,8 @@ public class FunctionObject extends BaseFunction {
? ctor.newInstance(invokeArgs)
: method.invoke(null, invokeArgs);
}
}
catch (InvocationTargetException e) {
Throwable target = e.getTargetException();
if (target instanceof EvaluatorException)
throw (EvaluatorException) target;
if (target instanceof EcmaError)
throw (EcmaError) target;
Scriptable scope = thisObj == null ? this : thisObj;
throw JavaScriptException.wrapException(cx, scope, target);
}
catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
}
catch (InstantiationException e) {
throw WrappedException.wrapException(e);
} catch (Exception ex) {
throw ScriptRuntime.throwAsUncheckedException(ex);
}
}

View File

@@ -1712,23 +1712,18 @@ public class Interpreter {
final int SCRIPT_CAN_CATCH = 0, ONLY_FINALLY = 1, OTHER = 2;
int exType;
for (;;) {
if (javaException instanceof JavaScriptException) {
exType = SCRIPT_CAN_CATCH;
} else if (javaException instanceof EcmaError) {
// an offical ECMA error object,
exType = SCRIPT_CAN_CATCH;
} else if (javaException instanceof WrappedException) {
WrappedException wex = (WrappedException)javaException;
javaException = wex.getWrappedException();
continue;
} else if (javaException instanceof RuntimeException) {
exType = ONLY_FINALLY;
} else {
// Error instance
exType = OTHER;
}
break;
if (javaException instanceof JavaScriptException) {
exType = SCRIPT_CAN_CATCH;
} else if (javaException instanceof EcmaError) {
// an offical ECMA error object,
exType = SCRIPT_CAN_CATCH;
} else if (javaException instanceof WrappedException) {
exType = SCRIPT_CAN_CATCH;
} else if (javaException instanceof RuntimeException) {
exType = ONLY_FINALLY;
} else {
// Error instance
exType = OTHER;
}
if (exType != OTHER) {

View File

@@ -141,7 +141,7 @@ public final class JavaAdapter
newInstance(ctorArgs);
return getAdapterSelf(adapterClass, adapter);
} catch (Exception ex) {
throw WrappedException.wrapException(ex);
throw ScriptRuntime.throwAsUncheckedException(ex);
}
}
@@ -362,7 +362,7 @@ public final class JavaAdapter
}
return ScriptRuntime.call(cx, fun, thisObj, args, object);
} catch (JavaScriptException ex) {
throw WrappedException.wrapException(ex);
throw ScriptRuntime.throwAsUncheckedException(ex);
} finally {
Context.exit();
}

View File

@@ -107,14 +107,8 @@ class JavaMembers {
rval = field.get(isStatic ? null : javaObject);
type = field.getType();
}
} catch (IllegalAccessException accEx) {
throw new RuntimeException("unexpected IllegalAccessException "+
"accessing Java field");
} catch (InvocationTargetException e) {
// Since JavaScriptException is a checked exception, must
// wrap the JavaScriptException in a WrappedException
throw WrappedException.wrapException(
JavaScriptException.wrapException(cx, scope, e));
} catch (Exception ex) {
throw ScriptRuntime.throwAsUncheckedException(ex);
}
// Need to wrap the object before we return it.
scope = ScriptableObject.getTopLevelScope(scope);
@@ -221,13 +215,8 @@ class JavaMembers {
Object[] args = { NativeJavaObject.coerceType(types[0], value,
true) };
method.invoke(javaObject, args);
} catch (IllegalAccessException accessEx) {
throw new RuntimeException("unexpected IllegalAccessException " +
"accessing Java field");
} catch (InvocationTargetException e) {
throw WrappedException.wrapException(
JavaScriptException.wrapException(
Context.getContext(), scope, e));
} catch (Exception ex) {
throw ScriptRuntime.throwAsUncheckedException(ex);
}
}
else {

View File

@@ -38,92 +38,32 @@
package org.mozilla.javascript;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Java reflection of JavaScript exceptions. (Possibly wrapping a Java exception.)
* Java reflection of JavaScript exceptions.
* Instances of this class are thrown by the JavaScript 'throw' keyword.
*
* @author Mike McCabe
*/
public class JavaScriptException extends Exception {
public class JavaScriptException extends Exception
{
/**
* <p>Pointer to initCause() method of Throwable.
* If this method does not exist,
* (i.e. we're running on something earlier than Java 1.4), the pointer will
* be null.</p>
*/
private static Method initCauseMethod = null;
static {
// Are we running on a JDK 1.4 or later system?
try {
Class ThrowableClass = ScriptRuntime.classOrNull(
"java.lang.Throwable");
initCauseMethod = ThrowableClass.getMethod("initCause",
new Class[]{ThrowableClass});
} catch (Exception ex) {
// Assume any exceptions means the method does not exist.
}
}
/**
* Create a JavaScript exception wrapping the given JavaScript value.
*
* Instances of this class are thrown by the JavaScript 'throw' keyword.
* Create a JavaScript exception wrapping the given JavaScript value
*
* @param value the JavaScript value thrown.
*/
public JavaScriptException(Object value) {
public JavaScriptException(Object value)
{
super(ScriptRuntime.toString(value));
if (value instanceof Throwable && initCauseMethod != null) {
try {
initCauseMethod.invoke(this, new Object[] {value});
} catch (Exception e) {
// Ignore any exceptions
}
}
this.value = value;
}
static JavaScriptException wrapException(Context cx, Scriptable scope,
Throwable exn)
{
if (exn instanceof InvocationTargetException)
exn = ((InvocationTargetException)exn).getTargetException();
if (exn instanceof JavaScriptException)
return (JavaScriptException)exn;
Object wrapper = cx.getWrapFactory().
wrap(cx, scope, exn, Throwable.class);
return new JavaScriptException(wrapper);
}
/**
* Get the exception value originally thrown. This may be a
* JavaScript value (null, undefined, Boolean, Number, String,
* Scriptable or Function) or a Java exception value thrown from a
* host object or from Java called through LiveConnect.
*
* @return the value wrapped by this exception
*/
public Object getValue() {
if (value != null && value instanceof Wrapper)
// this will also catch NativeStrings...
return ((Wrapper)value).unwrap();
else
return value;
public Object getValue()
{
return value;
}
/**
* The JavaScript exception value. This value is not
* intended for general use; if the JavaScriptException wraps a
* Java exception, getScriptableValue may return a Scriptable
* wrapping the original Java exception object.
*
* We would prefer to go through a getter to encapsulate the value,
* however that causes the bizarre error "nanosecond timeout value
* out of range" on the MS JVM.
* @serial
*/
Object value;
private Object value;
}

View File

@@ -63,7 +63,7 @@ public final class LazilyLoadedCtor {
ScriptableObject.DONTENUM);
}
catch (PropertyException e) {
throw WrappedException.wrapException(e);
throw ScriptRuntime.throwAsUncheckedException(e);
}
}
@@ -85,24 +85,10 @@ public final class LazilyLoadedCtor {
try {
ScriptableObject.defineClass(obj, cl, sealed);
isReplaced = true;
}
catch (InstantiationException e) {
throw WrappedException.wrapException(e);
}
catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
}
catch (InvocationTargetException e) {
throw WrappedException.wrapException(e);
}
catch (ClassDefinitionException e) {
throw WrappedException.wrapException(e);
}
catch (PropertyException e) {
throw WrappedException.wrapException(e);
}
catch (SecurityException ex) {
} catch (SecurityException ex) {
removeOnError = true;
} catch (Exception e) {
throw ScriptRuntime.throwAsUncheckedException(e);
}
}
if (removeOnError) {

View File

@@ -115,7 +115,7 @@ public class NativeFunction extends BaseFunction {
return null;
} catch (Exception ex) {
// Wrap the rest of exceptions including possible SecurityException
throw WrappedException.wrapException(ex);
throw ScriptRuntime.throwAsUncheckedException(ex);
}
}

View File

@@ -235,11 +235,11 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
String ctorString = ctor.toString();
throw Context.reportRuntimeError3(
"msg.bad.ctor.sig", argEx.getMessage(), ctorString, signature);
} catch (InvocationTargetException e) {
throw JavaScriptException.wrapException(cx, scope, e);
} catch (IllegalAccessException accessEx) {
throw Context.reportRuntimeError1(
"msg.java.internal.private", accessEx.getMessage());
} catch (Exception ex) {
throw ScriptRuntime.throwAsUncheckedException(ex);
}
// we need to force this to be wrapped, because construct _has_
// to return a scriptable

View File

@@ -228,50 +228,49 @@ public class NativeJavaMethod extends NativeFunction implements Function {
}
javaObject = ((Wrapper) o).unwrap();
}
try {
if (debug) {
printDebug("Calling ", meth, args);
}
if (debug) {
printDebug("Calling ", meth, args);
}
Object retval;
Object retval;
try {
try {
retval = meth.invoke(javaObject, args);
} catch (IllegalAccessException e) {
retval = retryIllegalAccessInvoke(meth, javaObject, args, e);
}
Class staticType = meth.getReturnType();
if (debug) {
Class actualType = (retval == null) ? null
: retval.getClass();
System.err.println(" ----- Returned " + retval +
" actual = " + actualType +
" expect = " + staticType);
}
Object wrapped = cx.getWrapFactory().wrap(cx, scope,
retval, staticType);
if (debug) {
Class actualType = (wrapped == null) ? null
: wrapped.getClass();
System.err.println(" ----- Wrapped as " + wrapped +
" class = " + actualType);
}
if (wrapped == Undefined.instance)
return wrapped;
if (wrapped == null && staticType == Void.TYPE)
return Undefined.instance;
return wrapped;
} catch (IllegalAccessException accessEx) {
throw Context.reportRuntimeError(
"While attempting to call \"" + meth.getName() +
"\" in class \"" + meth.getDeclaringClass().getName() +
"\" receieved " + accessEx.toString());
} catch (InvocationTargetException e) {
throw JavaScriptException.wrapException(cx, scope, e);
} catch (Exception ex) {
throw ScriptRuntime.throwAsUncheckedException(ex);
}
Class staticType = meth.getReturnType();
if (debug) {
Class actualType = (retval == null) ? null
: retval.getClass();
System.err.println(" ----- Returned " + retval +
" actual = " + actualType +
" expect = " + staticType);
}
Object wrapped = cx.getWrapFactory().wrap(cx, scope,
retval, staticType);
if (debug) {
Class actualType = (wrapped == null) ? null
: wrapped.getClass();
System.err.println(" ----- Wrapped as " + wrapped +
" class = " + actualType);
}
if (wrapped == Undefined.instance)
return wrapped;
if (wrapped == null && staticType == Void.TYPE)
return Undefined.instance;
return wrapped;
}
static Object retryIllegalAccessInvoke(Method method, Object obj,
@@ -321,7 +320,7 @@ public class NativeJavaMethod extends NativeFunction implements Function {
/**
* Find the correct function to call given the set of methods
* or constructors and the arguments.
* or constructors and the arguments.
* If no function can be found to call, return null.
*/
static Member findFunction(Member[] methodsOrCtors, Object[] args) {

View File

@@ -699,52 +699,62 @@ public class ScriptRuntime {
return (char)i;
}
/**
* Unwrap a JavaScriptException. Sleight of hand so that we don't
* javadoc JavaScriptException.getRuntimeValue().
*/
public static Object unwrapJavaScriptException(JavaScriptException jse) {
return jse.value;
}
/**
* Check a WrappedException. Unwrap a JavaScriptException and return
* the value, otherwise rethrow.
*/
public static Object unwrapWrappedException(WrappedException we) {
Throwable t = we.getWrappedException();
if (t instanceof JavaScriptException)
return ((JavaScriptException) t).value;
throw we;
}
/**
* Converts Java exceptions that JS can catch into an object the script
* will see as the catch argument.
*/
public static Object getCatchObject(Context cx, Scriptable scope,
Throwable exception)
Throwable t)
{
Object catchObj;
for (;;) {
if (exception instanceof JavaScriptException) {
catchObj = ScriptRuntime.unwrapJavaScriptException(
(JavaScriptException)exception);
} else if (exception instanceof EcmaError) {
// an offical ECMA error object,
catchObj = ((EcmaError)exception).getErrorObject();
} else if (exception instanceof WrappedException) {
WrappedException wex = (WrappedException)exception;
exception = wex.getWrappedException();
continue;
} else {
// catch can not be called with any other exceptions
Context.codeBug();
catchObj = null;
if (t instanceof JavaScriptException) {
return ((JavaScriptException)t).getValue();
} else if (t instanceof EcmaError) {
return ((EcmaError)t).getErrorObject();
} else {
if (!(t instanceof WrappedException)) Context.codeBug();
do {
t = ((WrappedException)t).getWrappedException();
} while (t instanceof WrappedException);
if (t instanceof JavaScriptException) {
return ((JavaScriptException)t).getValue();
} else if (t instanceof EcmaError) {
return ((EcmaError)t).getErrorObject();
}
break;
return cx.getWrapFactory().wrap(cx, scope, t, null);
}
}
/**
* Rethrow exception wrapped into {@link WrappedException} unless
* the exception is an instance of {@link EvaluatorExceptions},
* {@link EcmaError} or java.lang.Error which are rethrown as-is.
* <p>
* Instances of java.lang.reflect.InvocationTargetExceptions are treated
* specially. They are unwrapped and throwAsUncheckedException is applied
* recursively to its target.
* <p>
* This method always throws an exception, its return value is provided
* only for convenience to allow a usage like:
* <pre>
* throw ScriptRuntime.throwAsUncheckedException(ex);
* </pre>
* to indicate that code after the method is unreachable.
*/
public static RuntimeException throwAsUncheckedException(Throwable e)
{
while ((e instanceof InvocationTargetException)) {
e = ((InvocationTargetException) e).getTargetException();
}
return catchObj;
if (e instanceof Error) {
throw (Error)e;
}
if (e instanceof EvaluatorException) {
throw (EvaluatorException)e;
}
if (e instanceof EcmaError) {
throw (EcmaError)e;
}
throw new WrappedException(e);
}
public static Object getProp(Object obj, String id, Scriptable scope) {

View File

@@ -206,10 +206,8 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
try {
return slot.getter.invoke(getterThis, args);
} catch (InvocationTargetException e) {
throw WrappedException.wrapException(e);
} catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
} catch (Exception e) {
throw ScriptRuntime.throwAsUncheckedException(e);
}
}
@@ -308,10 +306,8 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
try {
setterResult = slot.setter.invoke(setterThis, args);
} catch (InvocationTargetException e) {
throw WrappedException.wrapException(e);
} catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
} catch (Exception e) {
throw ScriptRuntime.throwAsUncheckedException(e);
}
if (slot.setterReturnsValue) {

View File

@@ -35,6 +35,7 @@
package org.mozilla.javascript;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* A wrapper for runtime exceptions.
@@ -44,16 +45,45 @@ import java.lang.reflect.InvocationTargetException;
*
* @author Norris Boyd
*/
public class WrappedException extends EvaluatorException implements Wrapper {
public class WrappedException extends EvaluatorException
{
/**
* <p>Pointer to initCause() method of Throwable.
* If this method does not exist,
* (i.e. we're running on something earlier than Java 1.4), the pointer will
* be null.</p>
*/
private static Method initCauseMethod = null;
static {
// Are we running on a JDK 1.4 or later system?
try {
Class ThrowableClass = ScriptRuntime.classOrNull(
"java.lang.Throwable");
initCauseMethod = ThrowableClass.getMethod("initCause",
new Class[]{ThrowableClass});
} catch (Exception ex) {
// Assume any exceptions means the method does not exist.
}
}
/**
* Create a new exception wrapped around an existing exception.
*
* @param exception the exception to wrap
*/
public WrappedException(Throwable exception) {
public WrappedException(Throwable exception)
{
super(exception.getMessage());
this.exception = exception;
if (initCauseMethod != null) {
try {
initCauseMethod.invoke(this, new Object[] {exception});
} catch (Exception e) {
// Ignore any exceptions
}
}
}
/**
@@ -61,7 +91,8 @@ public class WrappedException extends EvaluatorException implements Wrapper {
*
* Delegates to the wrapped exception.
*/
public String getMessage() {
public String getMessage()
{
return "WrappedException of " + exception.toString();
}
@@ -70,7 +101,8 @@ public class WrappedException extends EvaluatorException implements Wrapper {
*
* Delegates to the wrapped exception.
*/
public String getLocalizedMessage() {
public String getLocalizedMessage()
{
return "WrappedException of " + exception.getLocalizedMessage();
}
@@ -80,36 +112,10 @@ public class WrappedException extends EvaluatorException implements Wrapper {
* @return the exception that was presented as a argument to the
* constructor when this object was created
*/
public Throwable getWrappedException() {
public Throwable getWrappedException()
{
return exception;
}
/**
* Get the wrapped exception.
*
* @return the exception that was presented as a argument to the
* constructor when this object was created
*/
public Object unwrap() {
return exception;
}
/**
* Wrap an exception.
*
* Provides special cases for EvaluatorExceptions (which are returned
* as-is), and InvocationTargetExceptions (which are unwrapped and
* passed to a recursive call to wrapException).<p>
*
* Otherwise the exception is simply wrapped in a WrappedException.
*/
public static EvaluatorException wrapException(Throwable e) {
if ((e instanceof InvocationTargetException))
e = ((InvocationTargetException) e).getTargetException();
if (e instanceof EvaluatorException)
return (EvaluatorException) e;
return new WrappedException(e);
}
private Throwable exception;
}

View File

@@ -150,7 +150,7 @@ public class Codegen extends Interpreter {
onlySave = true;
}
} catch (IOException iox) {
throw WrappedException.wrapException(iox);
throw ScriptRuntime.throwAsUncheckedException(iox);
}
}
@@ -182,7 +182,7 @@ public class Codegen extends Interpreter {
onlySave = true;
}
} catch (IOException iox) {
throw WrappedException.wrapException(iox);
throw ScriptRuntime.throwAsUncheckedException(iox);
}
}
}
@@ -2143,31 +2143,27 @@ public class Codegen extends Interpreter {
aload(savedVariableObject);
astore(variableObjectLocal);
aload(contextLocal);
aload(variableObjectLocal);
aload(exceptionObject);
releaseWordLocal(exceptionObject);
// unwrap the exception...
addScriptRuntimeInvoke(
"getCatchObject",
"(Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+"Ljava/lang/Throwable;"
+")Ljava/lang/Object;");
String exceptionName;
if (exceptionType == JAVASCRIPT_EXCEPTION) {
// unwrap the exception...
addScriptRuntimeInvoke(
"unwrapJavaScriptException",
"(Lorg/mozilla/javascript/JavaScriptException;"
+")Ljava/lang/Object;");
exceptionName = "org/mozilla/javascript/JavaScriptException";
} else if (exceptionType == WRAPPED_EXCEPTION) {
// unwrap the exception...
addScriptRuntimeInvoke(
"unwrapWrappedException",
"(Lorg/mozilla/javascript/WrappedException;"
+")Ljava/lang/Object;");
exceptionName = "org/mozilla/javascript/WrappedException";
} else {
if (exceptionType != ECMAERROR_EXCEPTION) Context.codeBug();
// unwrap the exception...
addVirtualInvoke("org/mozilla/javascript/EcmaError",
"getErrorObject",
"()Lorg/mozilla/javascript/Scriptable;");
exceptionName = "org/mozilla/javascript/EcmaError";
}